Skip to content

Commit

Permalink
Use promises in SDK, add some tests
Browse files Browse the repository at this point in the history
  • Loading branch information
olivier-lando committed Feb 2, 2021
1 parent a9349ea commit a71c615
Show file tree
Hide file tree
Showing 12 changed files with 9,988 additions and 921 deletions.
6 changes: 6 additions & 0 deletions .npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
tsconfig.json
tslint.json
webpack.config.js
node_modules
test
dist/test
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog
All changes to this project will be documented in this file.

## [1.2.2] - 2021-02-02
- getPaused, getMuted, getDuration, getCurrentTime, getVolume and getLoop now return promises
- Add some unit test

## [1.2.1] - 2021-01-15
- Add the possibility to specify metadata
19 changes: 9 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
![](https://github.com/apivideo/API_OAS_file/blob/master/apivideo_banner.png)

# player-sdk
# api.video player SDK

SDK to control and interact with the api.video HTML5 Player

# SDK usage
Expand Down Expand Up @@ -28,14 +29,12 @@ And then include the SDK with a simple `import { PlayerSdk } from '@api.video/pl

## Simple include in a javascript project

Download [the SDK from the github repository](https://github.com/apivideo/player-sdk)

Include the SDK in your HTML file like so:

```html
<head>
...
<script src="<SDK_HOST_TO_REPLACE>/index.js" defer></script>
<script src="https://unpkg.com/@api.video/player-sdk" defer></script>
</head>
```

Expand Down Expand Up @@ -96,17 +95,17 @@ Example:
player.volume(0.75); // Set the volume to 75%
```

#### `getPaused(callback: (paused: Boolean) => void)`
#### `getPaused(callback?: (paused: boolean) => void): Promise<boolean>`
Check weither the video is paused.
#### `getMuted(callback: (muted: Boolean) => void)`
#### `getMuted(callback?: (muted: boolean) => void): Promise<boolean>`
Check weither the video is muted.
#### `getDuration(callback: (duration: Number) => void)`
#### `getDuration(callback?: (duration: number) => void): Promise<number>`
Retrieve the duration of the video.
#### `getCurrentTime(callback: (currentTime: Number) => void)`
#### `getCurrentTime(callback?: (currentTime: number) => void): Promise<number>`
Retrieve the current playback time of the video.
#### `getVolume(callback: (volume: Number) => void)`
#### `getVolume(callback?: (volume: number) => void): Promise<number>`
Retrieve the current volume.
#### `getLoop(callback: (loop: Boolean) => void)`
#### `getLoop(callback?: (loop: boolean) => void): Promise<boolean>`
Check weither the video is in loop mode.

#### `destroy()`
Expand Down
12 changes: 6 additions & 6 deletions dist/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,12 @@ export declare class PlayerSdk {
setCurrentTime(time: number): void;
setVolume(volume: number): void;
setLoop(loop: boolean): void;
getPaused(callback: (paused: Boolean) => void): void;
getMuted(callback: (muted: Boolean) => void): void;
getDuration(callback: (duration: Number) => void): void;
getCurrentTime(callback: (currentTime: Number) => void): void;
getVolume(callback: (volume: Number) => void): void;
getLoop(callback: (loop: Boolean) => void): void;
getPaused(callback?: (paused: boolean) => void): Promise<boolean>;
getMuted(callback?: (muted: boolean) => void): Promise<boolean>;
getDuration(callback?: (duration: number) => void): Promise<number>;
getCurrentTime(callback?: (currentTime: number) => void): Promise<number>;
getVolume(callback?: (volume: number) => void): Promise<number>;
getLoop(callback?: (loop: boolean) => void): Promise<boolean>;
addEventListener(event: string, callback: () => void): void;
destroy(): void;
private urlParametersFromOptions;
Expand Down
2 changes: 1 addition & 1 deletion dist/index.js

Large diffs are not rendered by default.

121 changes: 67 additions & 54 deletions index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ type PlayerEvent = {

export class PlayerSdk {
private static DEFAULT_IFRAME_URL = "https://embed.api.video/${type}/${id}";
private iframe: HTMLIFrameElement|null = null;

private iframe: HTMLIFrameElement | null = null;
private playerReady: boolean = false;
private onceReadyCallbacks: (() => void)[] = [];
private userEventListeners: UserEventListener[] = [];
private sdkPlayerId: number;
private sdkOrigin: string;
private playerOrigin: string|null = null;
private playerOrigin: string | null = null;
private postMessageCallbacks: { [callbackId: string]: (arg: any) => void } = {};
private iframeUrl: string;

Expand All @@ -33,28 +33,28 @@ export class PlayerSdk {
if (target == null) {
throw new Error("No match found for selector " + targetSelector);
}
this.iframe = target.tagName !== "IFRAME"

this.iframe = target.tagName !== "IFRAME"
? this.createIframe(target)
: target as HTMLIFrameElement

options = options || {};
this.iframeUrl = options.iframeUrl || PlayerSdk.DEFAULT_IFRAME_URL;

if(!this.iframe.src) {
if (!this.iframe.src) {
this.createNewPlayer(this.iframe, options)
} else {
this.bindExistingPlayer(this.iframe);
}

this.onceReadyCallbacks = [];
this.userEventListeners = [];
this.playerReady = false;
this.playerOrigin = new URL(this.iframeUrl).origin;

window.addEventListener("message", (message) => {
if (message.origin === this.playerOrigin && message.data?.sdkPlayerId == this.sdkPlayerId) {
if(!!message.data.callbackId && !!this.postMessageCallbacks[message.data.callbackId]) {
if (message.origin === this.playerOrigin && message.data?.sdkPlayerId === this.sdkPlayerId) {
if (!!message.data.callbackId && !!this.postMessageCallbacks[message.data.callbackId]) {
this.postMessageCallbacks[message.data.callbackId](message.data.arg);
} else {
this.onEvent(message.data);
Expand All @@ -64,6 +64,9 @@ export class PlayerSdk {
}

createNewPlayer(iframe: HTMLIFrameElement, options: any) {
if(!options.id) {
throw new Error("Missing id in options");
}
const iframeUrl = this.iframeUrl
.replace("${id}", options.id)
.replace("${type}", options.live ? "live" : "vod");
Expand All @@ -76,7 +79,7 @@ export class PlayerSdk {
}

addParametersInIframeHash(url: string) {
url = this.addParameterInIframeHash(url, "sdkPlayerId", ""+this.sdkPlayerId);
url = this.addParameterInIframeHash(url, "sdkPlayerId", "" + this.sdkPlayerId);
url = this.addParameterInIframeHash(url, "sdkOrigin", btoa(this.sdkOrigin));
url = this.addParameterInIframeHash(url, "api");
return url;
Expand All @@ -86,12 +89,12 @@ export class PlayerSdk {
const indexOfHash = url.indexOf("#");
const parameterAndValue = value ? `${parameter}:${value}` : parameter;

if(indexOfHash === -1) {
if (indexOfHash === -1) {
return `${url}#${parameterAndValue}`;
}
const beforeHash = url.substr(0, indexOfHash);
let afterHash = url.substr(indexOfHash + 1);

afterHash = afterHash.replace(new RegExp(`${parameter}(:[^;]+)?;?`), "");

return `${beforeHash}#${parameterAndValue};${afterHash}`;
Expand Down Expand Up @@ -121,25 +124,25 @@ export class PlayerSdk {
setLoop(loop: boolean) {
this.postMessage({ message: 'setLoop', loop });
}
getPaused(callback: (paused: Boolean) => void) {
this.postMessage({ message: 'getPaused' }, callback);
getPaused(callback?: (paused: boolean) => void): Promise<boolean> {
return this.postMessage({ message: 'getPaused' }, callback);
}
getMuted(callback: (muted: Boolean) => void) {
this.postMessage({ message: 'getMuted' }, callback);
getMuted(callback?: (muted: boolean) => void): Promise<boolean> {
return this.postMessage({ message: 'getMuted' }, callback);
}
getDuration(callback: (duration: Number) => void) {
this.postMessage({ message: 'getDuration' }, callback);
getDuration(callback?: (duration: number) => void): Promise<number> {
return this.postMessage({ message: 'getDuration' }, callback);
}
getCurrentTime(callback: (currentTime: Number) => void) {
this.postMessage({ message: 'getCurrentTime' }, callback);
getCurrentTime(callback?: (currentTime: number) => void): Promise<number> {
return this.postMessage({ message: 'getCurrentTime' }, callback);
}
getVolume(callback: (volume: Number) => void) {
this.postMessage({ message: 'getVolume' }, callback);
getVolume(callback?: (volume: number) => void): Promise<number> {
return this.postMessage({ message: 'getVolume' }, callback);
}
getLoop(callback: (loop: Boolean) => void) {
this.postMessage({ message: 'getLoop' }, callback);
getLoop(callback?: (loop: boolean) => void): Promise<boolean> {
return this.postMessage({ message: 'getLoop' }, callback);
}



addEventListener(event: string, callback: () => void) {
Expand All @@ -153,10 +156,10 @@ export class PlayerSdk {

private urlParametersFromOptions(options: any) {
options.ts = new Date().getTime();
return Object.keys(options).map(function (key: string) {
if(key === "metadata" && options[key] instanceof Object) {
return Object.keys(options).map((key: string) => {
if (key === "metadata" && options[key] instanceof Object) {
const metadata = options[key];
return Object.keys(metadata).map(function (metadataName: string) {
return Object.keys(metadata).map((metadataName: string) => {
return "metadata[" + metadataName + "]=" + metadata[metadataName];
}).join("&");
}
Expand Down Expand Up @@ -185,40 +188,50 @@ export class PlayerSdk {
}
}

private postMessage(message: any, callback?: (arg: any) => void) {
if(!this.playerOrigin || !this.iframe?.contentWindow) {
return;
}
const messageWithPlayerId = {
...message,
sdkPlayerId: this.sdkPlayerId
}
private postMessage<T>(message: any, callback?: (arg: T) => void): Promise<T> {

return new Promise((resolve, reject): void => {

if (!this.playerOrigin || !this.iframe?.contentWindow) {
reject();
return;
}

const messageWithPlayerId = {
...message,
sdkPlayerId: this.sdkPlayerId
}

if(!!callback) {
const callbackId = this.makeId(16);
this.postMessageCallbacks[callbackId] = callback;
messageWithPlayerId.callbackId = callbackId;
}
this.postMessageCallbacks[callbackId] = (res: T) => {
resolve(res as T);
if (!!callback) {
callback(res);
}
};
messageWithPlayerId.callbackId = callbackId;

if (this.playerReady && !!this.playerOrigin) {
this.iframe.contentWindow.postMessage(messageWithPlayerId, this.playerOrigin);
} else {
this.onceReadyCallbacks.push(() => this.playerOrigin && this.iframe?.contentWindow?.postMessage(messageWithPlayerId, this.playerOrigin));
}

if (this.playerReady && !!this.playerOrigin) {
this.iframe.contentWindow.postMessage(messageWithPlayerId, this.playerOrigin);
} else {
this.onceReadyCallbacks.push(() => this.playerOrigin && this.iframe?.contentWindow?.postMessage(messageWithPlayerId, this.playerOrigin));
}
});
}

private makeId(length: number) {
var result = '';
var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
var charactersLength = characters.length;
for ( var i = 0; i < length; i++ ) {
result += characters.charAt(Math.floor(Math.random() * charactersLength));
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
const charactersLength = characters.length;
let result = '';
for (let i = 0; i < length; i++) {
result += characters.charAt(Math.floor(Math.random() * charactersLength));
}
return result;
}
}

private createIframe(target: Element) {
var ifr = document.createElement('iframe');
const ifr = document.createElement('iframe');
ifr.style.height = "100%";
ifr.style.width = "100%";
ifr.allowFullscreen = true;
Expand Down
Loading

0 comments on commit a71c615

Please sign in to comment.