mirror of
https://github.com/hensm/fx_cast.git
synced 2026-06-08 08:39:59 +00:00
Convert shim to Typescript (#32)
This commit is contained in:
43
ext/package-lock.json
generated
43
ext/package-lock.json
generated
@@ -3563,7 +3563,8 @@
|
||||
"ansi-regex": {
|
||||
"version": "2.1.1",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"aproba": {
|
||||
"version": "1.2.0",
|
||||
@@ -3584,12 +3585,14 @@
|
||||
"balanced-match": {
|
||||
"version": "1.0.0",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"balanced-match": "^1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
@@ -3604,17 +3607,20 @@
|
||||
"code-point-at": {
|
||||
"version": "1.1.0",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"concat-map": {
|
||||
"version": "0.0.1",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"console-control-strings": {
|
||||
"version": "1.1.0",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"core-util-is": {
|
||||
"version": "1.0.2",
|
||||
@@ -3731,7 +3737,8 @@
|
||||
"inherits": {
|
||||
"version": "2.0.3",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"ini": {
|
||||
"version": "1.3.5",
|
||||
@@ -3743,6 +3750,7 @@
|
||||
"version": "1.0.0",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"number-is-nan": "^1.0.0"
|
||||
}
|
||||
@@ -3757,6 +3765,7 @@
|
||||
"version": "3.0.4",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
}
|
||||
@@ -3764,12 +3773,14 @@
|
||||
"minimist": {
|
||||
"version": "0.0.8",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"minipass": {
|
||||
"version": "2.2.4",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"safe-buffer": "^5.1.1",
|
||||
"yallist": "^3.0.0"
|
||||
@@ -3788,6 +3799,7 @@
|
||||
"version": "0.5.1",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"minimist": "0.0.8"
|
||||
}
|
||||
@@ -3868,7 +3880,8 @@
|
||||
"number-is-nan": {
|
||||
"version": "1.0.1",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"object-assign": {
|
||||
"version": "4.1.1",
|
||||
@@ -3880,6 +3893,7 @@
|
||||
"version": "1.4.0",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
@@ -3965,7 +3979,8 @@
|
||||
"safe-buffer": {
|
||||
"version": "5.1.1",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"safer-buffer": {
|
||||
"version": "2.1.2",
|
||||
@@ -4001,6 +4016,7 @@
|
||||
"version": "1.0.2",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"code-point-at": "^1.0.0",
|
||||
"is-fullwidth-code-point": "^1.0.0",
|
||||
@@ -4020,6 +4036,7 @@
|
||||
"version": "3.0.1",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"ansi-regex": "^2.0.0"
|
||||
}
|
||||
@@ -4063,12 +4080,14 @@
|
||||
"wrappy": {
|
||||
"version": "1.0.2",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"yallist": {
|
||||
"version": "3.0.2",
|
||||
"bundled": true,
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -6915,7 +6934,7 @@
|
||||
},
|
||||
"pretty-format": {
|
||||
"version": "3.8.0",
|
||||
"resolved": "http://registry.npmjs.org/pretty-format/-/pretty-format-3.8.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-3.8.0.tgz",
|
||||
"integrity": "sha1-v77VbV6ad2ZF9LH/eqGjrE+jw4U=",
|
||||
"dev": true
|
||||
},
|
||||
|
||||
31
ext/src/global.d.ts
vendored
31
ext/src/global.d.ts
vendored
@@ -7,6 +7,37 @@ declare const APPLICATION_NAME: string;
|
||||
declare const APPLICATION_VERSION: string;
|
||||
|
||||
|
||||
declare interface Window {
|
||||
wrappedJSObject: typeof Window;
|
||||
}
|
||||
|
||||
|
||||
interface CloneIntoOptions {
|
||||
cloneFunctions?: boolean;
|
||||
wrapReflectors?: boolean;
|
||||
}
|
||||
|
||||
declare function cloneInto<T> (
|
||||
obj: T
|
||||
, targetScope: any
|
||||
, options?: CloneIntoOptions): T;
|
||||
|
||||
|
||||
interface ExportFunctionOptions {
|
||||
defineAs: string;
|
||||
allowCallbacks?: boolean;
|
||||
allowCrossOriginArguments?: boolean;
|
||||
}
|
||||
|
||||
type ExportFunctionFunc = (...args: any[]) => any;
|
||||
|
||||
declare function exportFunction (
|
||||
func: ExportFunctionFunc
|
||||
, targetScope: any
|
||||
, options?: ExportFunctionOptions): ExportFunctionFunc;
|
||||
|
||||
|
||||
|
||||
// Fix issues with @types/firefox-webext-browser
|
||||
declare namespace browser.events {
|
||||
/**
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
, "description": "__MSG_extensionDescription__"
|
||||
, "version": "EXTENSION_VERSION"
|
||||
|
||||
, "browser_specific_settings": {
|
||||
, "applications": {
|
||||
"gecko": {
|
||||
"id": "EXTENSION_ID"
|
||||
, "strict_min_version": "64.0"
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
import { AutoJoinPolicy
|
||||
, DefaultActionPolicy } from "../enums";
|
||||
|
||||
export default class ApiConfig {
|
||||
constructor (
|
||||
sessionRequest
|
||||
, sessionListener
|
||||
, receiverListener
|
||||
, opt_autoJoinPolicy = AutoJoinPolicy.TAB_AND_ORIGIN_SCOPED
|
||||
, opt_defaultActionPolicy = DefaultActionPolicy.CREATE_SESSION
|
||||
// TODO: Remove awful hack for mirror casting
|
||||
, selectedMedia = "app") {
|
||||
|
||||
this.autoJoinPolicy = opt_autoJoinPolicy;
|
||||
this.defaultActionPolicy = opt_defaultActionPolicy;
|
||||
this.receiverListener = receiverListener;
|
||||
this.sessionListener = sessionListener;
|
||||
this.sessionRequest = sessionRequest;
|
||||
|
||||
this.additionalSessionRequests = [];
|
||||
this.customDialLaunchCallback = null;
|
||||
this.invisibleSender = false;
|
||||
|
||||
this._selectedMedia = selectedMedia;
|
||||
}
|
||||
};
|
||||
25
ext/src/shim/cast/classes/ApiConfig.ts
Executable file
25
ext/src/shim/cast/classes/ApiConfig.ts
Executable file
@@ -0,0 +1,25 @@
|
||||
"use strict";
|
||||
|
||||
import Session from "./Session";
|
||||
import SessionRequest from "./SessionRequest";
|
||||
|
||||
import { AutoJoinPolicy
|
||||
, DefaultActionPolicy } from "../enums";
|
||||
|
||||
|
||||
export default class ApiConfig {
|
||||
public additionalSessionRequests: any[] = [];
|
||||
public customDialLaunchCallback: any = null;
|
||||
public invisibleSender = false;
|
||||
|
||||
constructor (
|
||||
public sessionRequest: SessionRequest
|
||||
, public sessionListener: (session: Session) => void
|
||||
, public receiverListener: (availability: string) => void
|
||||
, public autoJoinPolicy: string = AutoJoinPolicy.TAB_AND_ORIGIN_SCOPED
|
||||
, public defaultActionPolicy: string = DefaultActionPolicy.CREATE_SESSION
|
||||
|
||||
// TODO: Remove awful hack for mirror casting
|
||||
, public _selectedMedia: string = "app") {
|
||||
}
|
||||
};
|
||||
@@ -1,12 +1,9 @@
|
||||
"use strict";
|
||||
|
||||
// https://developers.google.com/cast/docs/reference/chrome/chrome.cast.DialRequest
|
||||
export default class DialRequest {
|
||||
constructor (
|
||||
appName
|
||||
, opt_launchParameter = null) {
|
||||
|
||||
this.appName = appName;
|
||||
this.launchParameter = opt_launchParameter;
|
||||
}
|
||||
};
|
||||
"use strict";
|
||||
|
||||
// https://developers.google.com/cast/docs/reference/chrome/chrome.cast.DialRequest
|
||||
export default class DialRequest {
|
||||
constructor (
|
||||
public appName: string
|
||||
, public launchParameter: string = null) {
|
||||
}
|
||||
};
|
||||
@@ -1,14 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
// https://developers.google.com/cast/docs/reference/chrome/chrome.cast.Error
|
||||
export default class Error {
|
||||
constructor (
|
||||
code
|
||||
, opt_description = null
|
||||
, opt_details = null) {
|
||||
|
||||
this.code = code;
|
||||
this.description = opt_description;
|
||||
this.details = opt_details;
|
||||
}
|
||||
};
|
||||
10
ext/src/shim/cast/classes/Error.ts
Executable file
10
ext/src/shim/cast/classes/Error.ts
Executable file
@@ -0,0 +1,10 @@
|
||||
"use strict";
|
||||
|
||||
// https://developers.google.com/cast/docs/reference/chrome/chrome.cast.Error
|
||||
export default class Error {
|
||||
constructor (
|
||||
public code: string
|
||||
, public description: string = null
|
||||
, public details: any = null) {
|
||||
}
|
||||
};
|
||||
@@ -1,11 +1,9 @@
|
||||
"use strict";
|
||||
|
||||
// https://developers.google.com/cast/docs/reference/chrome/chrome.cast.Image
|
||||
export default class Image {
|
||||
width = null;
|
||||
height = null;
|
||||
|
||||
constructor (url) {
|
||||
this.url = url;
|
||||
}
|
||||
};
|
||||
"use strict";
|
||||
|
||||
// https://developers.google.com/cast/docs/reference/chrome/chrome.cast.Image
|
||||
export default class Image {
|
||||
public width: number = null;
|
||||
public height: number = null;
|
||||
|
||||
constructor (public url: string) {}
|
||||
};
|
||||
@@ -1,22 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
import { Capability
|
||||
, ReceiverType } from "../enums";
|
||||
|
||||
// https://developers.google.com/cast/docs/reference/chrome/chrome.cast.Receiver
|
||||
export default class Receiver {
|
||||
constructor (
|
||||
label
|
||||
, friendlyName
|
||||
, opt_capabilities = []
|
||||
, opt_volume = null) {
|
||||
|
||||
this.capabilities = opt_capabilities;
|
||||
this.displayStatus = null;
|
||||
this.friendlyName = friendlyName;
|
||||
this.isActiveInput = null;
|
||||
this.label = label;
|
||||
this.receiverType = ReceiverType.CAST;
|
||||
this.volume = opt_volume;
|
||||
}
|
||||
};
|
||||
21
ext/src/shim/cast/classes/Receiver.ts
Executable file
21
ext/src/shim/cast/classes/Receiver.ts
Executable file
@@ -0,0 +1,21 @@
|
||||
"use strict";
|
||||
|
||||
import ReceiverDisplayStatus from "./ReceiverDisplayStatus";
|
||||
import Volume from "./Volume";
|
||||
|
||||
import { ReceiverType } from "../enums";
|
||||
|
||||
|
||||
// https://developers.google.com/cast/docs/reference/chrome/chrome.cast.Receiver
|
||||
export default class Receiver {
|
||||
public displayStatus: ReceiverDisplayStatus = null;
|
||||
public isActiveInput: boolean = null;
|
||||
public receiverType: string = ReceiverType.CAST;
|
||||
|
||||
constructor (
|
||||
public label: string
|
||||
, public friendlyName: string
|
||||
, public capabilities: string[] = []
|
||||
, public volume: Volume = null) {
|
||||
}
|
||||
};
|
||||
@@ -1,10 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
// https://developers.google.com/cast/docs/reference/chrome/chrome.cast.ReceiverDisplayStatus
|
||||
export default class ReceiverDisplayStatus {
|
||||
constructor (statusText, appImages) {
|
||||
this.appImages = appImages;
|
||||
this.showStop = null;
|
||||
this.statusText = statusText;
|
||||
}
|
||||
};
|
||||
13
ext/src/shim/cast/classes/ReceiverDisplayStatus.ts
Executable file
13
ext/src/shim/cast/classes/ReceiverDisplayStatus.ts
Executable file
@@ -0,0 +1,13 @@
|
||||
"use strict";
|
||||
|
||||
import Image from "./Image";
|
||||
|
||||
|
||||
// https://developers.google.com/cast/docs/reference/chrome/chrome.cast.ReceiverDisplayStatus
|
||||
export default class ReceiverDisplayStatus {
|
||||
public showStop: boolean = null;
|
||||
|
||||
constructor (
|
||||
public statusText: string
|
||||
, public appImages: Image[]) {}
|
||||
};
|
||||
@@ -1,10 +1,9 @@
|
||||
"use strict";
|
||||
|
||||
// https://developers.google.com/cast/docs/reference/chrome/chrome.cast.SenderApplication
|
||||
export default class SenderApplication {
|
||||
constructor (platform) {
|
||||
this.packageId = null;
|
||||
this.platform = platform;
|
||||
this.url = null;
|
||||
}
|
||||
};
|
||||
"use strict";
|
||||
|
||||
// https://developers.google.com/cast/docs/reference/chrome/chrome.cast.SenderApplication
|
||||
export default class SenderApplication {
|
||||
public packageId: string = null;
|
||||
public url: string = null;
|
||||
|
||||
constructor (public platform: string) {}
|
||||
};
|
||||
@@ -1,8 +1,16 @@
|
||||
"use strict";
|
||||
|
||||
import _Error from "./Error";
|
||||
import Volume from "./Volume";
|
||||
import Media from "../../media/classes/Media";
|
||||
import uuid from "uuid/v1";
|
||||
|
||||
import _Error from "./Error";
|
||||
import Image from "./Image";
|
||||
import Receiver from "./Receiver";
|
||||
import SenderApplication from "./SenderApplication";
|
||||
import Volume from "./Volume";
|
||||
|
||||
import LoadRequest from "../../media/classes/LoadRequest";
|
||||
import Media from "../../media/classes/Media";
|
||||
import QueueLoadRequest from "../../media/classes/QueueLoadRequest";
|
||||
|
||||
import { SessionStatus
|
||||
, ErrorCode
|
||||
@@ -10,44 +18,53 @@ import { SessionStatus
|
||||
|
||||
import { onMessage, sendMessageResponse } from "../../messageBridge";
|
||||
|
||||
import uuid from "uuid/v1";
|
||||
import { SuccessCallback
|
||||
, ErrorCallback
|
||||
, MediaListener
|
||||
, MessageListener
|
||||
, UpdateListener
|
||||
, LoadSuccessCallback
|
||||
, Callbacks
|
||||
, CallbacksMap } from "../../types";
|
||||
|
||||
|
||||
export default class Session {
|
||||
private _id: string = uuid();
|
||||
private _messageListeners = new Map<string, Set<MessageListener>>();
|
||||
private _updateListeners = new Set<UpdateListener>();
|
||||
|
||||
private _leaveCallbacks: CallbacksMap = new Map();
|
||||
private _sendMessageCallbacks: CallbacksMap = new Map();
|
||||
private _setReceiverMutedCallbacks: CallbacksMap = new Map();
|
||||
private _setReceiverVolumeLevelCallbacks: CallbacksMap = new Map();
|
||||
private _stopCallbacks: CallbacksMap = new Map();
|
||||
|
||||
public media: Media[];
|
||||
public namespaces: { name: "string" }[];
|
||||
public senderApps: SenderApplication[];
|
||||
public status: string;
|
||||
public statusText: string;
|
||||
public transportId: string;
|
||||
|
||||
constructor (
|
||||
sessionId
|
||||
, appId
|
||||
, displayName
|
||||
, appImages
|
||||
, receiver
|
||||
, successCallback) {
|
||||
|
||||
this._id = uuid();
|
||||
this._messageListeners = new Map();
|
||||
this._updateListeners = new Set();
|
||||
|
||||
this._sendMessageCallbacks = new Map();
|
||||
this._setReceiverMutedCallbacks = new Map();
|
||||
this._setReceiverVolumeLevelCallbacks = new Map();
|
||||
this._stopCallbacks = new Map();
|
||||
|
||||
this.sessionId = sessionId;
|
||||
this.transportId = sessionId || "";
|
||||
this.appId = appId;
|
||||
this.appImages = appImages;
|
||||
this.displayName = displayName;
|
||||
this.receiver = receiver;
|
||||
public sessionId: string
|
||||
, public appId: string
|
||||
, public displayName: string
|
||||
, public appImages: Image[]
|
||||
, public receiver: Receiver
|
||||
, successCallback: (session: Session) => void) {
|
||||
|
||||
this.media = [];
|
||||
this.namespaces = [];
|
||||
this.senderApps = [];
|
||||
this.status = SessionStatus.CONNECTED;
|
||||
this.statusText = null;
|
||||
this.transportId = sessionId || "";
|
||||
|
||||
if (receiver) {
|
||||
this._sendMessage("bridge:/session/initialize", {
|
||||
address: receiver._address
|
||||
, port: receiver._port
|
||||
address: (receiver as any)._address
|
||||
, port: (receiver as any)._port
|
||||
, appId
|
||||
, sessionId
|
||||
});
|
||||
@@ -62,7 +79,10 @@ export default class Session {
|
||||
switch (message.subject) {
|
||||
case "shim:/session/stopped": {
|
||||
this.status = SessionStatus.STOPPED;
|
||||
this._updateListeners.forEach(listener => listener());
|
||||
|
||||
for (const listener of this._updateListeners) {
|
||||
listener(false);
|
||||
}
|
||||
|
||||
break;
|
||||
};
|
||||
@@ -82,19 +102,21 @@ export default class Session {
|
||||
};
|
||||
|
||||
case "shim:/session/updateStatus": {
|
||||
if (message.data.volume) {
|
||||
const volume: Volume = message.data.volume;
|
||||
|
||||
if (volume) {
|
||||
if (!this.receiver.volume) {
|
||||
const receiverVolume = new Volume(
|
||||
message.data.volume.level
|
||||
, message.data.volume.muted);
|
||||
volume.level
|
||||
, volume.muted);
|
||||
|
||||
receiverVolume.controlType = message.data.volume.controlType;
|
||||
receiverVolume.stepInterval = message.data.volume.stepInterval;
|
||||
receiverVolume.controlType = volume.controlType;
|
||||
receiverVolume.stepInterval = volume.stepInterval;
|
||||
|
||||
this.receiver.volume = receiverVolume;
|
||||
} else {
|
||||
this.receiver.volume.level = message.data.volume.level;
|
||||
this.receiver.volume.muted = message.data.volume.muted;
|
||||
this.receiver.volume.level = volume.level;
|
||||
this.receiver.volume.muted = volume.muted;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,8 +126,10 @@ export default class Session {
|
||||
|
||||
case "shim:/session/impl_addMessageListener": {
|
||||
const { namespace, data } = message.data;
|
||||
this._messageListeners.get(namespace).forEach(
|
||||
listener => listener(namespace, data));
|
||||
for (const listener of this._messageListeners.get(namespace)) {
|
||||
listener(namespace, data);
|
||||
}
|
||||
|
||||
break;
|
||||
};
|
||||
|
||||
@@ -166,7 +190,10 @@ export default class Session {
|
||||
errorCallback(new _Error(ErrorCode.SESSION_ERROR));
|
||||
} else {
|
||||
this.status = SessionStatus.STOPPED;
|
||||
this._updateListeners.forEach(listener => listener());
|
||||
|
||||
for (const listener of this._updateListeners) {
|
||||
listener(false);
|
||||
}
|
||||
|
||||
if (successCallback) {
|
||||
successCallback();
|
||||
@@ -181,20 +208,12 @@ export default class Session {
|
||||
});
|
||||
}
|
||||
|
||||
_sendMessage (subject, data = {}) {
|
||||
sendMessageResponse({
|
||||
subject
|
||||
, data
|
||||
, _id: this._id
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
addMediaListener (listener) {
|
||||
public addMediaListener (listener: MediaListener) {
|
||||
console.info("STUB :: Session#addMediaListener")
|
||||
}
|
||||
|
||||
addMessageListener (namespace, listener) {
|
||||
public addMessageListener (namespace: string, listener: MessageListener) {
|
||||
if (!this._messageListeners.has(namespace)) {
|
||||
this._messageListeners.set(namespace, new Set());
|
||||
}
|
||||
@@ -204,11 +223,14 @@ export default class Session {
|
||||
});
|
||||
}
|
||||
|
||||
addUpdateListener (listener) {
|
||||
public addUpdateListener (listener: UpdateListener) {
|
||||
this._updateListeners.add(listener);
|
||||
}
|
||||
|
||||
leave (successCallback, errorCallback) {
|
||||
public leave (
|
||||
successCallback: SuccessCallback
|
||||
, errorCallback: ErrorCallback): void {
|
||||
|
||||
const id = uuid();
|
||||
|
||||
this._sendMessage("bridge:/session/impl_leave", { id });
|
||||
@@ -219,8 +241,12 @@ export default class Session {
|
||||
]);
|
||||
}
|
||||
|
||||
loadMedia (loadRequest, successCallback, errorCallback) {
|
||||
this.sendMediaMessage({
|
||||
public loadMedia (
|
||||
loadRequest: LoadRequest
|
||||
, successCallback: LoadSuccessCallback
|
||||
, errorCallback: ErrorCallback): void {
|
||||
|
||||
this._sendMediaMessage({
|
||||
type: "LOAD"
|
||||
, requestId: 0
|
||||
, media: loadRequest.media
|
||||
@@ -233,8 +259,10 @@ export default class Session {
|
||||
|
||||
let hasResponded = false;
|
||||
|
||||
this.addMessageListener("urn:x-cast:com.google.cast.media"
|
||||
this.addMessageListener(
|
||||
"urn:x-cast:com.google.cast.media"
|
||||
, (namespace, data) => {
|
||||
|
||||
if (hasResponded) return;
|
||||
|
||||
const mediaObject = JSON.parse(data);
|
||||
@@ -258,28 +286,38 @@ export default class Session {
|
||||
})
|
||||
}
|
||||
|
||||
queueLoad () {
|
||||
public queueLoad (
|
||||
queueLoadRequest: QueueLoadRequest
|
||||
, successCallback: LoadSuccessCallback
|
||||
, errorCallback: ErrorCallback): void {
|
||||
|
||||
console.info("STUB :: Session#queueLoad");
|
||||
}
|
||||
removeMediaListener (listener) {
|
||||
|
||||
public removeMediaListener (listener: MediaListener): void {
|
||||
console.info("STUB :: Session#removeMediaListener");
|
||||
}
|
||||
removeMessageListener (namespace, listener) {
|
||||
|
||||
public removeMessageListener (
|
||||
namespace: string
|
||||
, listener: MessageListener): void {
|
||||
|
||||
this._messageListeners.get(namespace).delete(listener);
|
||||
}
|
||||
removeUpdateListener (namespace, listener) {
|
||||
|
||||
public removeUpdateListener (
|
||||
namespace: string
|
||||
, listener: UpdateListener): void {
|
||||
|
||||
this._updateListeners.delete(listener);
|
||||
}
|
||||
|
||||
sendMediaMessage (message) {
|
||||
this.sendMessage(
|
||||
"urn:x-cast:com.google.cast.media"
|
||||
, message
|
||||
, () => {}
|
||||
, () => {});
|
||||
}
|
||||
public sendMessage (
|
||||
namespace: string
|
||||
, message: {} | string
|
||||
, successCallback: SuccessCallback
|
||||
, errorCallback: ErrorCallback): void {
|
||||
|
||||
sendMessage (namespace, message, successCallback, errorCallback) {
|
||||
const messageId = uuid();
|
||||
|
||||
this._sendMessage("bridge:/session/impl_sendMessage", {
|
||||
@@ -294,7 +332,11 @@ export default class Session {
|
||||
]);
|
||||
}
|
||||
|
||||
setReceiverMuted (muted, successCallback, errorCallback) {
|
||||
public setReceiverMuted (
|
||||
muted: boolean
|
||||
, successCallback: SuccessCallback
|
||||
, errorCallback: ErrorCallback) {
|
||||
|
||||
const volumeId = uuid();
|
||||
|
||||
this._sendMessage("bridge:/session/impl_setReceiverMuted", {
|
||||
@@ -308,7 +350,11 @@ export default class Session {
|
||||
]);
|
||||
}
|
||||
|
||||
setReceiverVolumeLevel (newLevel, successCallback, errorCallback) {
|
||||
public setReceiverVolumeLevel (
|
||||
newLevel: number
|
||||
, successCallback: SuccessCallback
|
||||
, errorCallback: ErrorCallback): void {
|
||||
|
||||
const volumeId = uuid();
|
||||
this._sendMessage("bridge:/session/impl_setReceiverVolumeLevel", {
|
||||
newLevel
|
||||
@@ -321,7 +367,10 @@ export default class Session {
|
||||
]);
|
||||
}
|
||||
|
||||
stop (successCallback, errorCallback) {
|
||||
public stop (
|
||||
successCallback: SuccessCallback
|
||||
, errorCallback: ErrorCallback): void {
|
||||
|
||||
const stopId = uuid();
|
||||
this._sendMessage("bridge:/session/impl_stop", { stopId });
|
||||
|
||||
@@ -330,4 +379,20 @@ export default class Session {
|
||||
, errorCallback
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
private _sendMessage (subject: string, data = {}) {
|
||||
sendMessageResponse({
|
||||
subject
|
||||
, data
|
||||
, _id: this._id
|
||||
});
|
||||
}
|
||||
|
||||
private _sendMediaMessage (message: string | {}) {
|
||||
this.sendMessage(
|
||||
"urn:x-cast:com.google.cast.media"
|
||||
, message
|
||||
, null, null);
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
import { Capability } from "../enums";
|
||||
import { requestSession as requestSessionTimeout } from "../../timeout.js";
|
||||
|
||||
// https://developers.google.com/cast/docs/reference/chrome/chrome.cast.SessionRequest
|
||||
export default class SessionRequest {
|
||||
constructor (
|
||||
appId
|
||||
, opt_capabilities = [
|
||||
Capability.VIDEO_OUT
|
||||
, Capability.AUDIO_OUT ]
|
||||
, opt_timeout = requestSessionTimeout) {
|
||||
|
||||
this.appId = appId;
|
||||
this.capabilities = opt_capabilities;
|
||||
this.dialRequest = null;
|
||||
this.language = null;
|
||||
this.requestSessionTimeout = opt_timeout;
|
||||
}
|
||||
};
|
||||
17
ext/src/shim/cast/classes/SessionRequest.ts
Executable file
17
ext/src/shim/cast/classes/SessionRequest.ts
Executable file
@@ -0,0 +1,17 @@
|
||||
"use strict";
|
||||
|
||||
import { Capability } from "../enums";
|
||||
import { requestSession } from "../../timeout";
|
||||
|
||||
// https://developers.google.com/cast/docs/reference/chrome/chrome.cast.SessionRequest
|
||||
export default class SessionRequest {
|
||||
public language: string = null;
|
||||
public dialRequest: any = null;
|
||||
|
||||
constructor (
|
||||
public appId: string
|
||||
, public capabilities = [
|
||||
Capability.VIDEO_OUT
|
||||
, Capability.AUDIO_OUT ]
|
||||
, public requestSessionTimeout: number = requestSession) {}
|
||||
};
|
||||
@@ -1,10 +1,10 @@
|
||||
"use strict";
|
||||
|
||||
import * as timeouts from "../../timeout.js";
|
||||
|
||||
// https://developers.google.com/cast/docs/reference/chrome/chrome.cast.Timeout
|
||||
export default class Timeout {
|
||||
constructor () {
|
||||
Object.assign(this, timeouts);
|
||||
}
|
||||
};
|
||||
"use strict";
|
||||
|
||||
import * as timeouts from "../../timeout";
|
||||
|
||||
// https://developers.google.com/cast/docs/reference/chrome/chrome.cast.Timeout
|
||||
export default class Timeout {
|
||||
constructor () {
|
||||
Object.assign(this, timeouts);
|
||||
}
|
||||
};
|
||||
@@ -1,13 +1,15 @@
|
||||
"use strict";
|
||||
|
||||
import { VolumeControlType } from "../enums";
|
||||
|
||||
// https://developers.google.com/cast/docs/reference/chrome/chrome.cast.Volume
|
||||
export default class Volume {
|
||||
constructor (
|
||||
opt_level = null
|
||||
, opt_muted = null) {
|
||||
this.level = opt_level;
|
||||
this.muted = opt_muted;
|
||||
}
|
||||
};
|
||||
"use strict";
|
||||
|
||||
import { VolumeControlType } from "../enums";
|
||||
|
||||
|
||||
// https://developers.google.com/cast/docs/reference/chrome/chrome.cast.Volume
|
||||
export default class Volume {
|
||||
public controlType: string;
|
||||
public stepInterval: number;
|
||||
|
||||
constructor (
|
||||
public level: number = null
|
||||
, public muted: boolean = null) {
|
||||
}
|
||||
};
|
||||
@@ -1,28 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
import ApiConfig from "./ApiConfig";
|
||||
import DialRequest from "./DialRequest";
|
||||
import Error_ from "./Error";
|
||||
import Image_ from "./Image";
|
||||
import Receiver from "./Receiver";
|
||||
import ReceiverDisplayStatus from "./ReceiverDisplayStatus";
|
||||
import SenderApplication from "./SenderApplication";
|
||||
import Session from "./Session";
|
||||
import SessionRequest from "./SessionRequest";
|
||||
import Timeout from "./Timeout";
|
||||
import Volume from "./Volume";
|
||||
|
||||
|
||||
export default {
|
||||
AutoJoinPolicy
|
||||
, Capability
|
||||
, DefaultActionPolicy
|
||||
, DialAppState
|
||||
, ErrorCode
|
||||
, ReceiverAction
|
||||
, ReceiverAvailability
|
||||
, ReceiverType
|
||||
, SenderPlatform
|
||||
, SessionStatus
|
||||
, VolumeControlType
|
||||
};
|
||||
@@ -1,75 +1,75 @@
|
||||
"use strict";
|
||||
|
||||
export const AutoJoinPolicy = {
|
||||
TAB_AND_ORIGIN_SCOPED: "tab_and_origin_scoped"
|
||||
, ORIGIN_SCOPED: "origin_scoped"
|
||||
, PAGE_SCOPED: "page_scoped"
|
||||
, CUSTOM_CONTROLLER_SCOPED: "custom_controller_scoped"
|
||||
};
|
||||
|
||||
export const Capability = {
|
||||
VIDEO_OUT: "video_out"
|
||||
, AUDIO_OUT: "audio_out"
|
||||
, VIDEO_IN: "video_in"
|
||||
, AUDIO_IN: "audio_in"
|
||||
, MULTIZONE_GROUP: "multizone_group"
|
||||
};
|
||||
|
||||
export const DefaultActionPolicy = {
|
||||
CREATE_SESSION: "create_session"
|
||||
, CAST_THIS_TAB: "cast_this_tab"
|
||||
};
|
||||
|
||||
export const DialAppState = {
|
||||
RUNNING: "running"
|
||||
, STOPPED: "stopped"
|
||||
, ERROR: "error"
|
||||
};
|
||||
|
||||
export const ErrorCode = {
|
||||
CANCEL: "cancel"
|
||||
, TIMEOUT: "timeout"
|
||||
, API_NOT_INITIALIZED: "api_not_initialized"
|
||||
, INVALID_PARAMETER: "invalid_parameter"
|
||||
, EXTENSION_NOT_COMPATIBLE: "extension_not_compatible"
|
||||
, EXTENSION_MISSING: "extension_missing"
|
||||
, RECEIVER_UNAVAILABLE: "receiver_unavailable"
|
||||
, SESSION_ERROR: "session_error"
|
||||
, CHANNEL_ERROR: "channel_error"
|
||||
, LOAD_MEDIA_FAILED: "load_media_failed"
|
||||
};
|
||||
|
||||
export const ReceiverAction = {
|
||||
CAST: "cast"
|
||||
, STOP: "stop"
|
||||
};
|
||||
|
||||
export const ReceiverAvailability = {
|
||||
AVAILABLE: "available"
|
||||
, UNAVAILABLE: "unavailable"
|
||||
};
|
||||
|
||||
export const ReceiverType = {
|
||||
CAST: "cast"
|
||||
, DIAL: "dial"
|
||||
, HANGOUT: "hangout"
|
||||
, CUSTOM: "custom"
|
||||
};
|
||||
|
||||
export const SenderPlatform = {
|
||||
CHROME: "chrome"
|
||||
, IOS: "ios"
|
||||
, ANDROID: "android"
|
||||
};
|
||||
|
||||
export const SessionStatus = {
|
||||
CONNECTED: "connected"
|
||||
, DISCONNECTED: "disconnected"
|
||||
, STOPPED: "stopped"
|
||||
};
|
||||
|
||||
export const VolumeControlType = {
|
||||
ATTENUATION: "attenuation"
|
||||
, FIXED: "fixed"
|
||||
, MASTER: "master"
|
||||
};
|
||||
"use strict";
|
||||
|
||||
export const AutoJoinPolicy = {
|
||||
TAB_AND_ORIGIN_SCOPED: "tab_and_origin_scoped"
|
||||
, ORIGIN_SCOPED: "origin_scoped"
|
||||
, PAGE_SCOPED: "page_scoped"
|
||||
, CUSTOM_CONTROLLER_SCOPED: "custom_controller_scoped"
|
||||
};
|
||||
|
||||
export const Capability = {
|
||||
VIDEO_OUT: "video_out"
|
||||
, AUDIO_OUT: "audio_out"
|
||||
, VIDEO_IN: "video_in"
|
||||
, AUDIO_IN: "audio_in"
|
||||
, MULTIZONE_GROUP: "multizone_group"
|
||||
};
|
||||
|
||||
export const DefaultActionPolicy = {
|
||||
CREATE_SESSION: "create_session"
|
||||
, CAST_THIS_TAB: "cast_this_tab"
|
||||
};
|
||||
|
||||
export const DialAppState = {
|
||||
RUNNING: "running"
|
||||
, STOPPED: "stopped"
|
||||
, ERROR: "error"
|
||||
};
|
||||
|
||||
export const ErrorCode = {
|
||||
CANCEL: "cancel"
|
||||
, TIMEOUT: "timeout"
|
||||
, API_NOT_INITIALIZED: "api_not_initialized"
|
||||
, INVALID_PARAMETER: "invalid_parameter"
|
||||
, EXTENSION_NOT_COMPATIBLE: "extension_not_compatible"
|
||||
, EXTENSION_MISSING: "extension_missing"
|
||||
, RECEIVER_UNAVAILABLE: "receiver_unavailable"
|
||||
, SESSION_ERROR: "session_error"
|
||||
, CHANNEL_ERROR: "channel_error"
|
||||
, LOAD_MEDIA_FAILED: "load_media_failed"
|
||||
};
|
||||
|
||||
export const ReceiverAction = {
|
||||
CAST: "cast"
|
||||
, STOP: "stop"
|
||||
};
|
||||
|
||||
export const ReceiverAvailability = {
|
||||
AVAILABLE: "available"
|
||||
, UNAVAILABLE: "unavailable"
|
||||
};
|
||||
|
||||
export const ReceiverType = {
|
||||
CAST: "cast"
|
||||
, DIAL: "dial"
|
||||
, HANGOUT: "hangout"
|
||||
, CUSTOM: "custom"
|
||||
};
|
||||
|
||||
export const SenderPlatform = {
|
||||
CHROME: "chrome"
|
||||
, IOS: "ios"
|
||||
, ANDROID: "android"
|
||||
};
|
||||
|
||||
export const SessionStatus = {
|
||||
CONNECTED: "connected"
|
||||
, DISCONNECTED: "disconnected"
|
||||
, STOPPED: "stopped"
|
||||
};
|
||||
|
||||
export const VolumeControlType = {
|
||||
ATTENUATION: "attenuation"
|
||||
, FIXED: "fixed"
|
||||
, MASTER: "master"
|
||||
};
|
||||
@@ -1,285 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
import ApiConfig from "./classes/ApiConfig";
|
||||
import DialRequest from "./classes/DialRequest";
|
||||
import Error_ from "./classes/Error";
|
||||
import Image_ from "./classes/Image";
|
||||
import Receiver from "./classes/Receiver";
|
||||
import ReceiverDisplayStatus from "./classes/ReceiverDisplayStatus";
|
||||
import SenderApplication from "./classes/SenderApplication";
|
||||
import Session from "./classes/Session";
|
||||
import SessionRequest from "./classes/SessionRequest";
|
||||
import Timeout from "./classes/Timeout";
|
||||
import Volume from "./classes/Volume";
|
||||
|
||||
import { AutoJoinPolicy
|
||||
, Capability
|
||||
, DefaultActionPolicy
|
||||
, DialAppState
|
||||
, ErrorCode
|
||||
, ReceiverAction
|
||||
, ReceiverAvailability
|
||||
, ReceiverType
|
||||
, SenderPlatform
|
||||
, SessionStatus
|
||||
, VolumeControlType } from "./enums";
|
||||
|
||||
import { requestSession as requestSessionTimeout } from "../timeout";
|
||||
|
||||
import state from "../state";
|
||||
|
||||
import { onMessage, sendMessageResponse } from "../messageBridge";
|
||||
|
||||
|
||||
const cast = {
|
||||
// Enums
|
||||
AutoJoinPolicy
|
||||
, Capability
|
||||
, DefaultActionPolicy
|
||||
, DialAppState
|
||||
, ErrorCode
|
||||
, ReceiverAction
|
||||
, ReceiverAvailability
|
||||
, ReceiverType
|
||||
, SenderPlatform
|
||||
, SessionStatus
|
||||
, VolumeControlType
|
||||
|
||||
// Classes
|
||||
, ApiConfig
|
||||
, DialRequest
|
||||
, Error: Error_
|
||||
, Image: Image_
|
||||
, Receiver
|
||||
, ReceiverDisplayStatus
|
||||
, SenderApplication
|
||||
, Session
|
||||
, SessionRequest
|
||||
, Timeout
|
||||
, Volume
|
||||
|
||||
, timeout: new Timeout()
|
||||
, isAvailable: true
|
||||
, VERSION: [ 1, 2 ]
|
||||
};
|
||||
|
||||
|
||||
const receiverListeners = new Set();
|
||||
|
||||
let sessionSuccessCallback;
|
||||
let sessionErrorCallback;
|
||||
|
||||
|
||||
cast.addReceiverActionListener = (listener) => {
|
||||
console.info("fx_cast (Debug): cast.addReceiverActionListener");
|
||||
receiverListeners.add(listener);
|
||||
};
|
||||
|
||||
cast.initialize = (
|
||||
apiConfig
|
||||
, successCallback
|
||||
, errorCallback) => {
|
||||
|
||||
console.info("fx_cast (Debug): cast.initialize");
|
||||
|
||||
// Already initialized
|
||||
if (state.apiConfig) {
|
||||
errorCallback(new Error_(ErrorCode.RECEIVER_UNAVAILABLE));
|
||||
return;
|
||||
}
|
||||
|
||||
state.apiConfig = apiConfig;
|
||||
|
||||
sendMessageResponse({
|
||||
subject: "bridge:/startDiscovery"
|
||||
});
|
||||
|
||||
apiConfig.receiverListener(state.receiverList.length
|
||||
? ReceiverAvailability.AVAILABLE
|
||||
: ReceiverAvailability.UNAVAILABLE);
|
||||
|
||||
successCallback();
|
||||
};
|
||||
|
||||
cast.logMessage = (message) => {
|
||||
console.log("CAST MSG:", message);
|
||||
};
|
||||
|
||||
cast.precache = (data) => {
|
||||
console.info("STUB :: cast.precache");
|
||||
};
|
||||
|
||||
cast.removeReceiverActionListener = (listener) => {
|
||||
receiverListeners.delete(listener);
|
||||
}
|
||||
|
||||
cast.requestSession = (
|
||||
successCallback
|
||||
, errorCallback
|
||||
, opt_sessionRequest = state.apiConfig.sessionRequest) => {
|
||||
|
||||
console.info("fx_cast (Debug): cast.requestSession");
|
||||
|
||||
// Called before initialization
|
||||
if (!state.apiConfig) {
|
||||
errorCallback(new Error_(ErrorCode.API_NOT_INITIALIZED));
|
||||
return;
|
||||
}
|
||||
|
||||
// Already requesting session
|
||||
if (state.sessionRequestInProgress) {
|
||||
errorCallback(new Error_(ErrorCode.INVALID_PARAMETER
|
||||
, "Session request already in progress."));
|
||||
return;
|
||||
}
|
||||
|
||||
// No available receivers
|
||||
if (!state.receiverList.length) {
|
||||
errorCallback(new Error_(ErrorCode.RECEIVER_UNAVAILABLE));
|
||||
return;
|
||||
}
|
||||
|
||||
state.sessionRequestInProgress = true;
|
||||
|
||||
sessionSuccessCallback = successCallback;
|
||||
sessionErrorCallback = errorCallback;
|
||||
|
||||
// Open destination chooser
|
||||
sendMessageResponse({
|
||||
subject: "main:/openPopup"
|
||||
});
|
||||
};
|
||||
|
||||
cast.requestSessionById = (sessionId) => {
|
||||
console.info("STUB :: cast.requestSessionById");
|
||||
};
|
||||
|
||||
cast.setCustomReceivers = (receivers, successCallback, errorCallback) => {
|
||||
console.info("STUB :: cast.setCustomReceivers");
|
||||
};
|
||||
|
||||
cast.setPageContext = (win) => {
|
||||
console.info("STUB :: cast.setPageContext");
|
||||
};
|
||||
|
||||
cast.setReceiverDisplayStatus = (sessionId) => {
|
||||
console.info("STUB :: cast.setReceiverDisplayStatus");
|
||||
};
|
||||
|
||||
cast.unescape = (escaped) => unescape(escaped);
|
||||
|
||||
|
||||
onMessage(message => {
|
||||
switch (message.subject) {
|
||||
/**
|
||||
* Cast destination found (serviceUp). Set the API availability
|
||||
* property and call the page event function (__onGCastApiAvailable).
|
||||
*/
|
||||
case "shim:/serviceUp": {
|
||||
const receiver = message.data;
|
||||
|
||||
if (state.receiverList.find(r => r.id === receiver.id)) {
|
||||
break;
|
||||
}
|
||||
|
||||
state.receiverList.push(receiver);
|
||||
|
||||
// Notify listeners of new cast destination
|
||||
state.apiConfig.receiverListener(ReceiverAvailability.AVAILABLE);
|
||||
|
||||
break;
|
||||
};
|
||||
|
||||
/**
|
||||
* Cast destination lost (serviceDown). Remove from the receiver list
|
||||
* and update availability state.
|
||||
*/
|
||||
case "shim:/serviceDown": {
|
||||
state.receiverList = state.receiverList.filter(
|
||||
receiver => receiver.id !== message.data.id);
|
||||
|
||||
if (state.receiverList.length === 0) {
|
||||
state.apiConfig.receiverListener(
|
||||
ReceiverAvailability.UNAVAILABLE);
|
||||
}
|
||||
|
||||
break;
|
||||
};
|
||||
|
||||
case "shim:/selectReceiver": {
|
||||
console.info("fx_cast (Debug): Selected receiver");
|
||||
|
||||
const selectedReceiver = new Receiver(
|
||||
message.data.receiver.id
|
||||
, message.data.receiver.friendlyName);
|
||||
|
||||
selectedReceiver._address = message.data.receiver.address;
|
||||
selectedReceiver._port = message.data.receiver.port;
|
||||
|
||||
const sessionConstructorArgs = [
|
||||
state.sessionList.length // sessionId
|
||||
, state.apiConfig.sessionRequest.appId // appId
|
||||
, selectedReceiver.friendlyName // displayName
|
||||
, [] // appImages
|
||||
, selectedReceiver // receiver
|
||||
, (session) => {
|
||||
sendMessageResponse({
|
||||
subject: "popup:/close"
|
||||
});
|
||||
|
||||
state.apiConfig.sessionListener(session);
|
||||
state.sessionRequestInProgress = false;
|
||||
sessionSuccessCallback(session, message.data.selectedMedia);
|
||||
}
|
||||
];
|
||||
|
||||
// If existing session active, stop it and start new one
|
||||
if (state.sessionList.length) {
|
||||
const lastSession
|
||||
= state.sessionList[state.sessionList.length - 1];
|
||||
|
||||
if (lastSession.status !== SessionStatus.STOPPED) {
|
||||
lastSession.stop(() => {
|
||||
state.sessionList.push(new Session(
|
||||
...sessionConstructorArgs));
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
state.sessionList.push(new Session(...sessionConstructorArgs));
|
||||
|
||||
break;
|
||||
};
|
||||
|
||||
/**
|
||||
* Popup is ready to receive data to populate the cast destination
|
||||
* chooser.
|
||||
*/
|
||||
case "shim:/popupReady": {
|
||||
sendMessageResponse({
|
||||
subject: "popup:/populateReceiverList"
|
||||
, data: {
|
||||
receivers: state.receiverList
|
||||
, selectedMedia: state.apiConfig._selectedMedia
|
||||
}
|
||||
});
|
||||
|
||||
break;
|
||||
};
|
||||
|
||||
/**
|
||||
* Popup closed before session established.
|
||||
*/
|
||||
case "shim:/popupClosed": {
|
||||
if (state.sessionRequestInProgress) {
|
||||
state.sessionRequestInProgress = false;
|
||||
sessionErrorCallback(new Error_(ErrorCode.CANCEL));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export default cast;
|
||||
288
ext/src/shim/cast/index.ts
Executable file
288
ext/src/shim/cast/index.ts
Executable file
@@ -0,0 +1,288 @@
|
||||
"use strict";
|
||||
|
||||
import ApiConfig from "./classes/ApiConfig";
|
||||
import DialRequest from "./classes/DialRequest";
|
||||
import Error_ from "./classes/Error";
|
||||
import Image_ from "./classes/Image";
|
||||
import Receiver from "./classes/Receiver";
|
||||
import ReceiverDisplayStatus from "./classes/ReceiverDisplayStatus";
|
||||
import SenderApplication from "./classes/SenderApplication";
|
||||
import Session from "./classes/Session";
|
||||
import SessionRequest from "./classes/SessionRequest";
|
||||
import Timeout from "./classes/Timeout";
|
||||
import Volume from "./classes/Volume";
|
||||
|
||||
import { AutoJoinPolicy
|
||||
, Capability
|
||||
, DefaultActionPolicy
|
||||
, DialAppState
|
||||
, ErrorCode
|
||||
, ReceiverAction
|
||||
, ReceiverAvailability
|
||||
, ReceiverType
|
||||
, SenderPlatform
|
||||
, SessionStatus
|
||||
, VolumeControlType } from "./enums";
|
||||
|
||||
|
||||
import { requestSession as requestSessionTimeout } from "../timeout";
|
||||
|
||||
import { onMessage, sendMessageResponse } from "../messageBridge";
|
||||
|
||||
|
||||
|
||||
type ReceiverActionListener = (
|
||||
receiver: Receiver
|
||||
, receiverAction: typeof ReceiverAction) => void;
|
||||
|
||||
type RequestSessionSuccessCallback = (session: Session, selectedMedia: string) => void;
|
||||
|
||||
type SuccessCallback = () => void;
|
||||
type ErrorCallback = (err: Error_) => void;
|
||||
|
||||
|
||||
let apiConfig: ApiConfig;
|
||||
let receiverList: any[] = [];
|
||||
let sessionList: Session[] = [];
|
||||
let sessionRequestInProgress = false;
|
||||
|
||||
let receiverListeners = new Set<ReceiverActionListener>();
|
||||
|
||||
let sessionSuccessCallback: RequestSessionSuccessCallback;
|
||||
let sessionErrorCallback: ErrorCallback;
|
||||
|
||||
export default {
|
||||
// Enums
|
||||
AutoJoinPolicy, Capability, DefaultActionPolicy, DialAppState
|
||||
, ErrorCode, ReceiverAction, ReceiverAvailability, ReceiverType
|
||||
, SenderPlatform, SessionStatus, VolumeControlType
|
||||
|
||||
// Classes
|
||||
, ApiConfig, DialRequest, Error: Error_, Image: Image_
|
||||
, Receiver, ReceiverDisplayStatus, SenderApplication, Session
|
||||
, SessionRequest, Timeout, Volume
|
||||
|
||||
, VERSION: [1, 2]
|
||||
, isAvailable: false
|
||||
, timeout: new Timeout()
|
||||
|
||||
|
||||
, addReceiverActionListener: (
|
||||
listener: ReceiverActionListener): void => {
|
||||
|
||||
console.info("fx_cast (Debug): cast.addReceiverActionListener");
|
||||
receiverListeners.add(listener);
|
||||
}
|
||||
|
||||
, initialize: (
|
||||
newApiConfig: ApiConfig
|
||||
, successCallback: SuccessCallback
|
||||
, errorCallback: ErrorCallback): void => {
|
||||
|
||||
console.info("fx_cast (Debug): cast.initialize");
|
||||
|
||||
// Already initialized
|
||||
if (apiConfig) {
|
||||
errorCallback(new Error_(ErrorCode.RECEIVER_UNAVAILABLE));
|
||||
return;
|
||||
}
|
||||
|
||||
apiConfig = newApiConfig;
|
||||
|
||||
sendMessageResponse({
|
||||
subject: "bridge:/startDiscovery"
|
||||
});
|
||||
|
||||
console.log(receiverList.length)
|
||||
|
||||
apiConfig.receiverListener(receiverList.length
|
||||
? ReceiverAvailability.AVAILABLE
|
||||
: ReceiverAvailability.UNAVAILABLE);
|
||||
|
||||
successCallback();
|
||||
}
|
||||
|
||||
, logMessage: (message: string): void => {
|
||||
console.log("CAST MSG:", message);
|
||||
}
|
||||
|
||||
, precache: (data: string): void => {
|
||||
console.info("STUB :: cast.precache");
|
||||
}
|
||||
|
||||
, removeReceiverActionListener: (
|
||||
listener: ReceiverActionListener): void => {
|
||||
|
||||
receiverListeners.delete(listener);
|
||||
}
|
||||
|
||||
, requestSession: (
|
||||
successCallback: RequestSessionSuccessCallback
|
||||
, errorCallback: ErrorCallback
|
||||
, sessionRequest: SessionRequest = apiConfig.sessionRequest): void => {
|
||||
|
||||
console.info("fx_cast (Debug): cast.requestSession");
|
||||
|
||||
// Called before initialization
|
||||
if (!apiConfig) {
|
||||
errorCallback(new Error_(ErrorCode.API_NOT_INITIALIZED));
|
||||
return;
|
||||
}
|
||||
|
||||
// Already requesting session
|
||||
if (sessionRequestInProgress) {
|
||||
errorCallback(new Error_(ErrorCode.INVALID_PARAMETER
|
||||
, "Session request already in progress."));
|
||||
return;
|
||||
}
|
||||
|
||||
// No available receivers
|
||||
if (!receiverList.length) {
|
||||
errorCallback(new Error_(ErrorCode.RECEIVER_UNAVAILABLE));
|
||||
return;
|
||||
}
|
||||
|
||||
sessionRequestInProgress = true;
|
||||
|
||||
sessionSuccessCallback = successCallback;
|
||||
sessionErrorCallback = errorCallback;
|
||||
|
||||
// Open destination chooser
|
||||
sendMessageResponse({
|
||||
subject: "main:/openPopup"
|
||||
});
|
||||
}
|
||||
|
||||
, requestSessionById: (sessionId: string): void => {
|
||||
console.info("STUB :: cast.requestSessionById");
|
||||
}
|
||||
|
||||
, setCustomReceivers: (
|
||||
receivers: Receiver[]
|
||||
, successCallback: SuccessCallback
|
||||
, errorCallback: ErrorCallback): void => {
|
||||
|
||||
console.info("STUB :: cast.setCustomReceivers");
|
||||
}
|
||||
|
||||
, setPageContext: (win: Window): void => {
|
||||
console.info("STUB :: cast.setPageContext");
|
||||
}
|
||||
|
||||
, setReceiverDisplayStatus: (sessionId: string): void => {
|
||||
console.info("STUB :: cast.setReceiverDisplayStatus");
|
||||
}
|
||||
|
||||
, unescape: (escaped: string): string => {
|
||||
return unescape(escaped);
|
||||
}
|
||||
}
|
||||
|
||||
onMessage(message => {
|
||||
switch (message.subject) {
|
||||
/**
|
||||
* Cast destination found (serviceUp). Set the API availability
|
||||
* property and call the page event function (__onGCastApiAvailable).
|
||||
*/
|
||||
case "shim:/serviceUp": {
|
||||
const receiver = message.data;
|
||||
|
||||
if (receiverList.find(r => r.id === receiver.id)) {
|
||||
break;
|
||||
}
|
||||
|
||||
receiverList.push(receiver);
|
||||
|
||||
// Notify listeners of new cast destination
|
||||
apiConfig.receiverListener(ReceiverAvailability.AVAILABLE);
|
||||
|
||||
break;
|
||||
};
|
||||
|
||||
/**
|
||||
* Cast destination lost (serviceDown). Remove from the receiver list
|
||||
* and update availability state.
|
||||
*/
|
||||
case "shim:/serviceDown": {
|
||||
receiverList = receiverList.filter(
|
||||
receiver => receiver.id !== message.data.id);
|
||||
|
||||
if (receiverList.length === 0) {
|
||||
apiConfig.receiverListener(
|
||||
ReceiverAvailability.UNAVAILABLE);
|
||||
}
|
||||
|
||||
break;
|
||||
};
|
||||
|
||||
case "shim:/selectReceiver": {
|
||||
console.info("fx_cast (Debug): Selected receiver");
|
||||
|
||||
const selectedReceiver = new Receiver(
|
||||
message.data.receiver.id
|
||||
, message.data.receiver.friendlyName);
|
||||
|
||||
(selectedReceiver as any)._address = message.data.receiver.address;
|
||||
(selectedReceiver as any)._port = message.data.receiver.port;
|
||||
|
||||
function createSession () {
|
||||
sessionList.push(new Session(
|
||||
sessionList.length.toString() // sessionId
|
||||
, apiConfig.sessionRequest.appId // appId
|
||||
, selectedReceiver.friendlyName // displayName
|
||||
, [] // appImages
|
||||
, selectedReceiver // receiver
|
||||
, (session: Session) => {
|
||||
sendMessageResponse({
|
||||
subject: "popup:/close"
|
||||
});
|
||||
|
||||
apiConfig.sessionListener(session);
|
||||
sessionRequestInProgress = false;
|
||||
sessionSuccessCallback(session, message.data.selectedMedia);
|
||||
}));
|
||||
}
|
||||
|
||||
// If an existing session is active, stop it and start new one
|
||||
if (sessionList.length) {
|
||||
const lastSession = sessionList[sessionList.length - 1];
|
||||
|
||||
if (lastSession.status !== SessionStatus.STOPPED) {
|
||||
lastSession.stop(createSession, null);
|
||||
}
|
||||
} else {
|
||||
createSession();
|
||||
}
|
||||
|
||||
break;
|
||||
};
|
||||
|
||||
/**
|
||||
* Popup is ready to receive data to populate the cast destination
|
||||
* chooser.
|
||||
*/
|
||||
case "shim:/popupReady": {
|
||||
sendMessageResponse({
|
||||
subject: "popup:/populateReceiverList"
|
||||
, data: {
|
||||
receivers: receiverList
|
||||
, selectedMedia: apiConfig._selectedMedia
|
||||
}
|
||||
});
|
||||
|
||||
break;
|
||||
};
|
||||
|
||||
/**
|
||||
* Popup closed before session established.
|
||||
*/
|
||||
case "shim:/popupClosed": {
|
||||
if (sessionRequestInProgress) {
|
||||
sessionRequestInProgress = false;
|
||||
sessionErrorCallback(new Error_(ErrorCode.CANCEL));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -1,34 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
import { onMessageResponse, sendMessage } from "./messageBridge";
|
||||
|
||||
|
||||
const backgroundPort = browser.runtime.connect({
|
||||
name: "shim"
|
||||
});
|
||||
backgroundPort.onMessage.addListener(sendMessage);
|
||||
|
||||
let popupPort;
|
||||
browser.runtime.onConnect.addListener(port => {
|
||||
if (port.name === "popup") {
|
||||
popupPort = port;
|
||||
}
|
||||
port.onMessage.addListener(sendMessage)
|
||||
});
|
||||
|
||||
onMessageResponse(message => {
|
||||
const [ destination ] = message.subject.split(":/");
|
||||
switch (destination) {
|
||||
case "popup": {
|
||||
if (popupPort) {
|
||||
popupPort.postMessage(message);
|
||||
}
|
||||
|
||||
break;
|
||||
};
|
||||
|
||||
default: {
|
||||
backgroundPort.postMessage(message);
|
||||
}
|
||||
}
|
||||
});
|
||||
34
ext/src/shim/content.ts
Normal file
34
ext/src/shim/content.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
"use strict";
|
||||
|
||||
import { Message } from "../types";
|
||||
import { onMessageResponse, sendMessage } from "./messageBridge";
|
||||
|
||||
// Message ports
|
||||
const backgroundPort = browser.runtime.connect({ name: "shim" });
|
||||
let popupPort: browser.runtime.Port;
|
||||
|
||||
|
||||
// Set popupPort once it connects
|
||||
browser.runtime.onConnect.addListener(port => {
|
||||
if (port.name === "popup") {
|
||||
popupPort = port;
|
||||
}
|
||||
|
||||
port.onMessage.addListener(sendMessage);
|
||||
});
|
||||
|
||||
// Forward background messages to shim
|
||||
backgroundPort.onMessage.addListener(sendMessage);
|
||||
|
||||
// Forward shim messages to popup and background script
|
||||
onMessageResponse((message: Message) => {
|
||||
const [ destination ] = message.subject.split(":/");
|
||||
|
||||
if (destination === "popup") {
|
||||
if (popupPort) {
|
||||
popupPort.postMessage(message);
|
||||
}
|
||||
} else {
|
||||
backgroundPort.postMessage(message);
|
||||
}
|
||||
});
|
||||
@@ -1,3 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
window.wrappedJSObject.chrome = cloneInto({}, window);
|
||||
3
ext/src/shim/contentSetup.ts
Normal file
3
ext/src/shim/contentSetup.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
"use strict";
|
||||
|
||||
(window.wrappedJSObject as any).chrome = cloneInto({}, window);
|
||||
@@ -1,17 +1,19 @@
|
||||
"use strict";
|
||||
|
||||
import cast from "./cast";
|
||||
import cast from "./cast";
|
||||
import media from "./media";
|
||||
|
||||
import { onMessage } from "./messageBridge";
|
||||
|
||||
|
||||
if (!window.chrome) {
|
||||
window.chrome = {};
|
||||
const global = (window as any);
|
||||
|
||||
if (!global.chrome) {
|
||||
global.chrome = {};
|
||||
}
|
||||
|
||||
window.chrome.cast = cast;
|
||||
window.chrome.cast.media = media;
|
||||
global.chrome.cast = cast;
|
||||
global.chrome.cast.media = media;
|
||||
|
||||
|
||||
onMessage(message => {
|
||||
@@ -20,11 +22,12 @@ onMessage(message => {
|
||||
const bridgeInfo = message.data;
|
||||
|
||||
// Call page's API loaded function if defined
|
||||
const readyFunction = window.__onGCastApiAvailable;
|
||||
const readyFunction = global.__onGCastApiAvailable;
|
||||
if (readyFunction && typeof readyFunction === "function") {
|
||||
readyFunction(bridgeInfo && bridgeInfo.isVersionCompatible);
|
||||
}
|
||||
|
||||
break;
|
||||
};
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -1,9 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
export default class EditTracksInfoRequest {
|
||||
constructor (opt_activeTrackIds = null, opt_textTrackStyle = null) {
|
||||
this.activeTrackIds = opt_activeTrackIds;
|
||||
this.requestId = 0;
|
||||
this.textTrackStyle = opt_textTrackStyle;
|
||||
}
|
||||
}
|
||||
10
ext/src/shim/media/classes/EditTracksInfoRequest.ts
Normal file
10
ext/src/shim/media/classes/EditTracksInfoRequest.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
"use strict";
|
||||
|
||||
export default class EditTracksInfoRequest {
|
||||
public requestId = 0;
|
||||
|
||||
constructor (
|
||||
public activeTrackIds: number[] = null
|
||||
, public textTrackStyle: string = null) {
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
import { MetadataType } from "../enums";
|
||||
|
||||
export default class GenericMediaMetadata {
|
||||
constructor () {
|
||||
this.images = null;
|
||||
this.metadataType = MetadataType.GENERIC;
|
||||
this.releaseDate = null;
|
||||
this.releaseYear = null;
|
||||
this.subtitle = null;
|
||||
this.title = null;
|
||||
this.type = MetadataType.GENERIC;
|
||||
}
|
||||
}
|
||||
16
ext/src/shim/media/classes/GenericMediaMetadata.ts
Normal file
16
ext/src/shim/media/classes/GenericMediaMetadata.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
"use strict";
|
||||
|
||||
import Image from "../../cast/classes/Image";
|
||||
|
||||
import { MetadataType } from "../enums";
|
||||
|
||||
|
||||
export default class GenericMediaMetadata {
|
||||
public images: Image[] = null;
|
||||
public metadataType: number = MetadataType.GENERIC;
|
||||
public releaseDate: string = null;
|
||||
public releaseYear: number = null;
|
||||
public subtitle: string = null;
|
||||
public title: string = null;
|
||||
public type: number = MetadataType.GENERIC;
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
export default class GetStatusRequest {
|
||||
constructor () {
|
||||
this.customData = null;
|
||||
}
|
||||
}
|
||||
5
ext/src/shim/media/classes/GetStatusRequest.ts
Normal file
5
ext/src/shim/media/classes/GetStatusRequest.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
export default class GetStatusRequest {
|
||||
public customData: any = null;
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
export default class LoadRequest {
|
||||
constructor (mediaInfo) {
|
||||
this.activeTrackIds = null;
|
||||
this.autoplay = true;
|
||||
this.currentTime = null;
|
||||
this.customData = null;
|
||||
this.media = mediaInfo;
|
||||
this.requestId = 0;
|
||||
this.sessionId = null;
|
||||
this.type = "LOAD";
|
||||
}
|
||||
}
|
||||
19
ext/src/shim/media/classes/LoadRequest.ts
Normal file
19
ext/src/shim/media/classes/LoadRequest.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
"use strict";
|
||||
|
||||
import MediaInfo from "./MediaInfo";
|
||||
|
||||
|
||||
export default class LoadRequest {
|
||||
public activeTrackIds: number[] = null;
|
||||
public autoplay: boolean = true;
|
||||
public currentTime: number = null;
|
||||
public customData: any = null;
|
||||
public media: MediaInfo;
|
||||
public requestId: number = 0;
|
||||
public sessionId: string = null;
|
||||
public type: string = "LOAD";
|
||||
|
||||
constructor (mediaInfo: MediaInfo) {
|
||||
this.media = mediaInfo;
|
||||
}
|
||||
}
|
||||
@@ -1,197 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
|
||||
import Volume from "../../cast/classes/Volume";
|
||||
|
||||
import { PlayerState
|
||||
, RepeatMode
|
||||
, MediaCommand } from "../enums";
|
||||
|
||||
import _Error from "../../cast/classes/Error";
|
||||
import { ErrorCode } from "../../cast/enums";
|
||||
|
||||
import { onMessage, sendMessageResponse } from "../../messageBridge";
|
||||
|
||||
import uuid from "uuid/v1";
|
||||
|
||||
|
||||
export default class Media {
|
||||
constructor (sessionId, mediaSessionId, _internalSessionId) {
|
||||
this._id = uuid();
|
||||
|
||||
this.activeTrackIds = null;
|
||||
this.currentItemId = null;
|
||||
this.customData = null;
|
||||
this.currentTime = 0;
|
||||
this.idleReason = null;
|
||||
this.items = null;
|
||||
this.loadingItemId = null;
|
||||
this.media = null;
|
||||
this.mediaSessionId = mediaSessionId;
|
||||
this.playbackRate = 1;
|
||||
this.playerState = PlayerState.IDLE;
|
||||
this.preloadedItemId = null;
|
||||
this.repeatMode = RepeatMode.OFF;
|
||||
this.sessionId = sessionId;
|
||||
this.supportedMediaCommands = [];
|
||||
this.volume = new Volume();
|
||||
|
||||
this._sendMessage("bridge:/media/initialize", {
|
||||
sessionId
|
||||
, mediaSessionId
|
||||
, _internalSessionId
|
||||
});
|
||||
|
||||
onMessage(message => {
|
||||
if (!message._id || message._id !== this._id) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (message.subject) {
|
||||
case "shim:/media/update":
|
||||
const status = message.data;
|
||||
this.currentTime = status.currentTime;
|
||||
this._lastCurrentTime = status._lastCurrentTime;
|
||||
this.customData = status.customData;
|
||||
this.volume = new Volume(
|
||||
status._volumeLevel
|
||||
, status._volumeMuted);
|
||||
this.playbackRate = status.playbackRate;
|
||||
this.playerState = status.playerState;
|
||||
this.repeatMode = status.repeatMode;
|
||||
|
||||
if (status.media) {
|
||||
this.media = status.media;
|
||||
}
|
||||
if (status.mediaSessionId) {
|
||||
this.mediaSessionId = status.mediaSessionId;
|
||||
}
|
||||
|
||||
// Call update listeners
|
||||
this._updateListeners.forEach(listener => listener(true));
|
||||
|
||||
break;
|
||||
|
||||
case "shim:/media/sendMediaMessageResponse":
|
||||
const { messageId, error } = message.data;
|
||||
const [ successCallback, errorCallback ]
|
||||
= this._sendMediaMessageCallbacks.get(messageId);
|
||||
|
||||
if (error && errorCallback) {
|
||||
errorCallback(new _Error(ErrorCode.SESSION_ERROR));
|
||||
} else if (successCallback) {
|
||||
successCallback();
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
this._updateListeners = new Set();
|
||||
this._sendMediaMessageCallbacks = new Map();
|
||||
}
|
||||
|
||||
_sendMessage (subject, data) {
|
||||
sendMessageResponse({
|
||||
subject
|
||||
, data
|
||||
, _id: this._id
|
||||
});
|
||||
}
|
||||
|
||||
_sendMediaMessage (message, successCallback, errorCallback) {
|
||||
message.mediaSessionId = this.mediaSessionId;
|
||||
message.requestId = 0;
|
||||
message.sessionId = this.sessionId;
|
||||
message.customData = null;
|
||||
|
||||
const messageId = uuid();
|
||||
|
||||
this._sendMediaMessageCallbacks.set(messageId, [
|
||||
successCallback
|
||||
, errorCallback
|
||||
]);
|
||||
|
||||
this._sendMessage("bridge:/media/sendMediaMessage", {
|
||||
message
|
||||
, messageId
|
||||
});
|
||||
}
|
||||
|
||||
addUpdateListener (listener) {
|
||||
this._updateListeners.add(listener);
|
||||
}
|
||||
editTracksInfo (editTracksInfoRequest, successCallback, errorCallback) {
|
||||
console.log("STUB :: Media#editTracksInfo");
|
||||
}
|
||||
getEstimatedTime () {
|
||||
if (!this.currentTime) return 0;
|
||||
return this.currentTime + ((Date.now() / 1000) - this._lastCurrentTime);
|
||||
}
|
||||
getStatus (getStatusRequest, successCallback, errorCallback) {
|
||||
this._sendMediaMessage({ type: "MEDIA_GET_STATUS" }
|
||||
, successCallback, errorCallback);
|
||||
}
|
||||
pause (pauseRequest, successCallback, errorCallback) {
|
||||
this._sendMediaMessage({ type: "PAUSE" }
|
||||
, successCallback, errorCallback);
|
||||
}
|
||||
play (playRequest, successCallback, errorCallback) {
|
||||
this._sendMediaMessage({ type: "PLAY" }
|
||||
, successCallback, errorCallback);
|
||||
}
|
||||
queueAppendItem (item, successCallback, errorCallback) {
|
||||
console.log("STUB :: Media#queueAppendItem");
|
||||
}
|
||||
queueInsertItems (queueInsertItemsRequest, successCallback, errorCallback) {
|
||||
console.log("STUB :: Media#queueInsertItems");
|
||||
}
|
||||
queueJumpToItem (itemId, successCallback, errorCallback) {
|
||||
console.log("STUB :: Media#queueJumpToItem");
|
||||
}
|
||||
queueMoveItemToNewIndex (itemId, newIndex, successCallback, errorCallback) {
|
||||
console.log("STUB :: Media#queueMoveItemToNewIndex");
|
||||
}
|
||||
queueNext (successCallback, errorCallback) {
|
||||
console.log("STUB :: Media#queueNext");
|
||||
}
|
||||
queuePrev (successCallback, errorCallback) {
|
||||
console.log("STUB :: Media#queuePrev");
|
||||
}
|
||||
queueRemoveItem(itemId, successCallback, errorCallback) {
|
||||
console.log("STUB :: Media#queueRemoveItem");
|
||||
}
|
||||
queueReorderItems (queueReorderItemsRequest, successCallback, errorCallback) {
|
||||
console.log("STUB :: Media#queueReorderItems");
|
||||
}
|
||||
queueSetRepeatMode (repeatMode, successCallback, errorCallback) {
|
||||
console.log("STUB :: Media#queueSetRepeatMode");
|
||||
}
|
||||
queueUpdateItems (queueUpdateItemsRequest, successCallback, errorCallback) {
|
||||
console.log("STUB :: Media#queueUpdateItems");
|
||||
}
|
||||
removeUpdateListener (listener) {
|
||||
this._updateListeners.delete(listener);
|
||||
}
|
||||
seek (seekRequest, successCallback, errorCallback) {
|
||||
console.log(seekRequest);
|
||||
this._sendMediaMessage({
|
||||
type: "SEEK"
|
||||
, currentTime: seekRequest.currentTime
|
||||
}, successCallback, errorCallback);
|
||||
}
|
||||
setVolume (volumeRequest, successCallback, errorCallback) {
|
||||
this._sendMediaMessage({
|
||||
type: "SET_VOLUME"
|
||||
, volume: volumeRequest.volume
|
||||
}, successCallback, errorCallback);
|
||||
}
|
||||
stop (stopRequest, successCallback, errorCallback) {
|
||||
this._sendMediaMessage({ type: "STOP" }
|
||||
, successCallback, errorCallback);
|
||||
}
|
||||
supportsCommand (command) {
|
||||
console.log("STUB :: Media#supportsCommand");
|
||||
}
|
||||
}
|
||||
311
ext/src/shim/media/classes/Media.ts
Normal file
311
ext/src/shim/media/classes/Media.ts
Normal file
@@ -0,0 +1,311 @@
|
||||
"use strict";
|
||||
|
||||
import uuid from "uuid/v1";
|
||||
|
||||
import EditTracksInfoRequest from "./EditTracksInfoRequest";
|
||||
import GetStatusRequest from "./GetStatusRequest";
|
||||
import PauseRequest from "./PauseRequest";
|
||||
import PlayRequest from "./PlayRequest";
|
||||
import QueueInsertItemsRequest from "./QueueInsertItemsRequest";
|
||||
import QueueReorderItemsRequest from "./QueueReorderItemsRequest";
|
||||
import QueueUpdateItemsRequest from "./QueueUpdateItemsRequest";
|
||||
import SeekRequest from "./SeekRequest";
|
||||
import VolumeRequest from "./VolumeRequest";
|
||||
import StopRequest from "./StopRequest";
|
||||
import MediaInfo from "./MediaInfo";
|
||||
import QueueItem from "./QueueItem";
|
||||
|
||||
import Volume from "../../cast/classes/Volume";
|
||||
|
||||
import { PlayerState
|
||||
, RepeatMode
|
||||
, MediaCommand } from "../enums";
|
||||
|
||||
import _Error from "../../cast/classes/Error";
|
||||
import { ErrorCode } from "../../cast/enums";
|
||||
|
||||
import { onMessage, sendMessageResponse } from "../../messageBridge";
|
||||
|
||||
import { SuccessCallback
|
||||
, ErrorCallback
|
||||
, UpdateListener
|
||||
, Callbacks
|
||||
, CallbacksMap } from "../../types";
|
||||
|
||||
|
||||
export default class Media {
|
||||
private _id: string = uuid();
|
||||
|
||||
private _updateListeners = new Set<UpdateListener>();
|
||||
private _sendMediaMessageCallbacks: CallbacksMap = new Map();
|
||||
|
||||
private _lastCurrentTime: number;
|
||||
|
||||
|
||||
public activeTrackIds: number[] = null;
|
||||
public currentItemId: number = null;
|
||||
public customData: any = null;
|
||||
public currentTime: number = 0;
|
||||
public idleReason: string = null;
|
||||
public items: QueueItem[] = null;
|
||||
public loadingItemId: number = null;
|
||||
public media: MediaInfo = null;
|
||||
public playbackRate: number = 1;
|
||||
public playerState: string = PlayerState.IDLE;
|
||||
public preloadedItemId: number = null;
|
||||
public repeatMode: string = RepeatMode.OFF;
|
||||
public supportedMediaCommands: string[] = [];
|
||||
public volume: Volume = new Volume();
|
||||
|
||||
constructor (
|
||||
public sessionId: string
|
||||
, public mediaSessionId: number
|
||||
, _internalSessionId: string) {
|
||||
|
||||
this._sendMessage("bridge:/media/initialize", {
|
||||
sessionId
|
||||
, mediaSessionId
|
||||
, _internalSessionId
|
||||
});
|
||||
|
||||
onMessage(message => {
|
||||
if (!message._id || message._id !== this._id) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (message.subject) {
|
||||
case "shim:/media/update": {
|
||||
const status = message.data;
|
||||
|
||||
this.currentTime = status.currentTime;
|
||||
this._lastCurrentTime = status._lastCurrentTime;
|
||||
this.customData = status.customData;
|
||||
this.volume = new Volume(
|
||||
status._volumeLevel
|
||||
, status._volumeMuted);
|
||||
this.playbackRate = status.playbackRate;
|
||||
this.playerState = status.playerState;
|
||||
this.repeatMode = status.repeatMode;
|
||||
|
||||
if (status.media) {
|
||||
this.media = status.media;
|
||||
}
|
||||
if (status.mediaSessionId) {
|
||||
this.mediaSessionId = status.mediaSessionId;
|
||||
}
|
||||
|
||||
// Call update listeners
|
||||
for (const listener of this._updateListeners) {
|
||||
listener(true);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case "shim:/media/sendMediaMessageResponse": {
|
||||
const { messageId, error } = message.data;
|
||||
const [ successCallback, errorCallback ]
|
||||
= this._sendMediaMessageCallbacks.get(messageId);
|
||||
|
||||
if (error && errorCallback) {
|
||||
errorCallback(new _Error(ErrorCode.SESSION_ERROR));
|
||||
} else if (successCallback) {
|
||||
successCallback();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public addUpdateListener (listener: UpdateListener): void {
|
||||
this._updateListeners.add(listener);
|
||||
}
|
||||
|
||||
public editTracksInfo (
|
||||
editTracksInfoRequest: EditTracksInfoRequest
|
||||
, successCallback?: SuccessCallback
|
||||
, errorCallback?: ErrorCallback): void {
|
||||
|
||||
console.log("STUB :: Media#editTracksInfo");
|
||||
}
|
||||
|
||||
public getEstimatedTime (): number {
|
||||
if (!this.currentTime) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return this.currentTime
|
||||
+ ((Date.now() / 1000) - this._lastCurrentTime);
|
||||
}
|
||||
|
||||
public getStatus (
|
||||
getStatusRequest?: GetStatusRequest
|
||||
, successCallback?: SuccessCallback
|
||||
, errorCallback?: ErrorCallback) {
|
||||
|
||||
this._sendMediaMessage({ type: "MEDIA_GET_STATUS" }
|
||||
, successCallback, errorCallback);
|
||||
}
|
||||
|
||||
public pause (
|
||||
pauseRequest: PauseRequest
|
||||
, successCallback?: SuccessCallback
|
||||
, errorCallback?: ErrorCallback) {
|
||||
|
||||
this._sendMediaMessage({ type: "PAUSE" }
|
||||
, successCallback, errorCallback);
|
||||
}
|
||||
|
||||
public play (
|
||||
playRequest?: PlayRequest
|
||||
, successCallback?: SuccessCallback
|
||||
, errorCallback?: ErrorCallback) {
|
||||
|
||||
this._sendMediaMessage({ type: "PLAY" }
|
||||
, successCallback, errorCallback);
|
||||
}
|
||||
|
||||
public queueAppendItem (
|
||||
item: QueueItem
|
||||
, successCallback?: SuccessCallback
|
||||
, errorCallback?: ErrorCallback) {
|
||||
console.log("STUB :: Media#queueAppendItem");
|
||||
}
|
||||
|
||||
public queueInsertItems (
|
||||
queueInsertItemsRequest: QueueInsertItemsRequest
|
||||
, successCallback?: SuccessCallback
|
||||
, errorCallback?: ErrorCallback) {
|
||||
console.log("STUB :: Media#queueInsertItems");
|
||||
}
|
||||
|
||||
public queueJumpToItem (
|
||||
itemId: number
|
||||
, successCallback?: SuccessCallback
|
||||
, errorCallback?: ErrorCallback) {
|
||||
console.log("STUB :: Media#queueJumpToItem");
|
||||
}
|
||||
|
||||
public queueMoveItemToNewIndex (
|
||||
itemId: number
|
||||
, newIndex: number
|
||||
, successCallback?: SuccessCallback
|
||||
, errorCallback?: ErrorCallback) {
|
||||
console.log("STUB :: Media#queueMoveItemToNewIndex");
|
||||
}
|
||||
|
||||
public queueNext (
|
||||
successCallback?: SuccessCallback
|
||||
, errorCallback?: ErrorCallback) {
|
||||
console.log("STUB :: Media#queueNext");
|
||||
}
|
||||
|
||||
public queuePrev (
|
||||
successCallback?: SuccessCallback
|
||||
, errorCallback?: ErrorCallback) {
|
||||
console.log("STUB :: Media#queuePrev");
|
||||
}
|
||||
|
||||
public queueRemoveItem(
|
||||
itemId: number
|
||||
, successCallback?: SuccessCallback
|
||||
, errorCallback?: ErrorCallback) {
|
||||
console.log("STUB :: Media#queueRemoveItem");
|
||||
}
|
||||
|
||||
public queueReorderItems (
|
||||
queueReorderItemsRequest: QueueReorderItemsRequest
|
||||
, successCallback?: SuccessCallback
|
||||
, errorCallback?: ErrorCallback) {
|
||||
console.log("STUB :: Media#queueReorderItems");
|
||||
}
|
||||
|
||||
public queueSetRepeatMode (
|
||||
repeatMode: string
|
||||
, successCallback?: SuccessCallback
|
||||
, errorCallback?: ErrorCallback) {
|
||||
console.log("STUB :: Media#queueSetRepeatMode");
|
||||
}
|
||||
|
||||
public queueUpdateItems (
|
||||
queueUpdateItemsRequest: QueueUpdateItemsRequest
|
||||
, successCallback?: SuccessCallback
|
||||
, errorCallback?: ErrorCallback) {
|
||||
console.log("STUB :: Media#queueUpdateItems");
|
||||
}
|
||||
|
||||
public removeUpdateListener (listener: UpdateListener) {
|
||||
this._updateListeners.delete(listener);
|
||||
}
|
||||
|
||||
public seek (
|
||||
seekRequest: SeekRequest
|
||||
, successCallback?: SuccessCallback
|
||||
, errorCallback?: ErrorCallback) {
|
||||
|
||||
this._sendMediaMessage({
|
||||
type: "SEEK"
|
||||
, currentTime: seekRequest.currentTime
|
||||
}, successCallback, errorCallback);
|
||||
}
|
||||
|
||||
public setVolume (
|
||||
volumeRequest: VolumeRequest
|
||||
, successCallback?: SuccessCallback
|
||||
, errorCallback?: ErrorCallback) {
|
||||
|
||||
this._sendMediaMessage({
|
||||
type: "SET_VOLUME"
|
||||
, volume: volumeRequest.volume
|
||||
}, successCallback, errorCallback);
|
||||
}
|
||||
|
||||
public stop (
|
||||
stopRequest: StopRequest
|
||||
, successCallback?: SuccessCallback
|
||||
, errorCallback?: ErrorCallback) {
|
||||
|
||||
this._sendMediaMessage({
|
||||
type: "STOP"
|
||||
}, successCallback, errorCallback);
|
||||
}
|
||||
|
||||
public supportsCommand (command: string) {
|
||||
console.log("STUB :: Media#supportsCommand");
|
||||
}
|
||||
|
||||
|
||||
private _sendMessage (subject: string, data: {}) {
|
||||
sendMessageResponse({
|
||||
subject
|
||||
, data
|
||||
, _id: this._id
|
||||
});
|
||||
}
|
||||
|
||||
private _sendMediaMessage (
|
||||
message: any
|
||||
, successCallback?: SuccessCallback
|
||||
, errorCallback?: ErrorCallback) {
|
||||
|
||||
message.mediaSessionId = this.mediaSessionId;
|
||||
message.requestId = 0;
|
||||
message.sessionId = this.sessionId;
|
||||
message.customData = null;
|
||||
|
||||
const messageId = uuid();
|
||||
|
||||
this._sendMediaMessageCallbacks.set(messageId, [
|
||||
successCallback
|
||||
, errorCallback
|
||||
]);
|
||||
|
||||
this._sendMessage("bridge:/media/sendMediaMessage", {
|
||||
message
|
||||
, messageId
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
import { StreamType } from "../enums";
|
||||
|
||||
export default class MediaInfo {
|
||||
constructor (contentId, contentType) {
|
||||
this.contentId = contentId;
|
||||
this.contentType = contentType;
|
||||
this.customData = null;
|
||||
this.duration = null;
|
||||
this.metadata = null;
|
||||
this.streamType = StreamType.BUFFERED;
|
||||
this.textTrackStyle = null;
|
||||
this.tracks = null;
|
||||
}
|
||||
}
|
||||
33
ext/src/shim/media/classes/MediaInfo.ts
Normal file
33
ext/src/shim/media/classes/MediaInfo.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
"use strict";
|
||||
|
||||
import GenericMediaMetadata from "./GenericMediaMetadata";
|
||||
import MovieMediaMetadata from "./MovieMediaMetadata";
|
||||
import MusicTrackMediaMetadata from "./MusicTrackMediaMetadata";
|
||||
import PhotoMediaMetadata from "./PhotoMediaMetadata";
|
||||
import TvShowMediaMetadata from "./TvShowMediaMetadata";
|
||||
|
||||
import TextTrackStyle from "./TextTrackStyle";
|
||||
import Track from "./Track";
|
||||
|
||||
import { StreamType } from "../enums";
|
||||
|
||||
|
||||
type Metadata =
|
||||
GenericMediaMetadata
|
||||
| MovieMediaMetadata
|
||||
| MusicTrackMediaMetadata
|
||||
| PhotoMediaMetadata
|
||||
| TvShowMediaMetadata;
|
||||
|
||||
export default class MediaInfo {
|
||||
public customData: string = null;
|
||||
public duration: number = null;
|
||||
public metadata: Metadata = null;
|
||||
public streamType: string = StreamType.BUFFERED;
|
||||
public textTrackStyle: TextTrackStyle = null;
|
||||
public tracks: Track[] = null;
|
||||
|
||||
constructor (
|
||||
public contentId: string
|
||||
, public contentType: string) {}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
import { MetadataType } from "../enums";
|
||||
|
||||
export default class MovieMediaMetadata {
|
||||
constructor () {
|
||||
this.images = null;
|
||||
this.metadataType = MetadataType.MOVIE;
|
||||
this.releaseDate = null;
|
||||
this.releaseYear = null;
|
||||
this.studio = null;
|
||||
this.subtitle = null;
|
||||
this.title = null;
|
||||
this.type = MetadataType.MOVIE;
|
||||
}
|
||||
}
|
||||
17
ext/src/shim/media/classes/MovieMediaMetadata.ts
Normal file
17
ext/src/shim/media/classes/MovieMediaMetadata.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
"use strict";
|
||||
|
||||
import Image from "../../cast/classes/Image";
|
||||
|
||||
import { MetadataType } from "../enums";
|
||||
|
||||
|
||||
export default class MovieMediaMetadata {
|
||||
public images: Image[] = null;
|
||||
public metadataType: number = MetadataType.MOVIE;
|
||||
public releaseDate: string = null;
|
||||
public releaseYear: number = null;
|
||||
public studio: string = null;
|
||||
public subtitle: string = null;
|
||||
public title: string = null;
|
||||
public type: number = MetadataType.MOVIE;
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
import { MetadataType } from "../enums";
|
||||
|
||||
export default class MusicTrackMediaMetadata {
|
||||
constructor () {
|
||||
this.albumArtist = null;
|
||||
this.albumName = null;
|
||||
this.artist = null;
|
||||
this.artistName = null;
|
||||
this.composer = null;
|
||||
this.discNumber = null;
|
||||
this.images = null;
|
||||
this.metadataType = MetadataType.MUSIC_TRACK;
|
||||
this.releaseDate = null;
|
||||
this.releaseYear = null;
|
||||
this.songName = null;
|
||||
this.title = null;
|
||||
this.trackNumber = null;
|
||||
this.type = MetadataType.MUSIC_TRACK;
|
||||
}
|
||||
}
|
||||
23
ext/src/shim/media/classes/MusicTrackMediaMetadata.ts
Normal file
23
ext/src/shim/media/classes/MusicTrackMediaMetadata.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
"use strict";
|
||||
|
||||
import Image from "../../cast/classes/Image";
|
||||
|
||||
import { MetadataType } from "../enums";
|
||||
|
||||
|
||||
export default class MusicTrackMediaMetadata {
|
||||
public albumArtist: string = null;
|
||||
public albumName: string = null;
|
||||
public artist: string = null;
|
||||
public artistName: string = null;
|
||||
public composer: string = null;
|
||||
public discNumber: number = null;
|
||||
public images: Image[] = null;
|
||||
public metadataType: number = MetadataType.MUSIC_TRACK;
|
||||
public releaseDate: string = null;
|
||||
public releaseYear: number = null;
|
||||
public songName: string = null;
|
||||
public title: string = null;
|
||||
public trackNumber: number = null;
|
||||
public type: number = MetadataType.MUSIC_TRACK;
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
export default class PauseRequest {
|
||||
constructor () {
|
||||
this.customData = null;
|
||||
}
|
||||
}
|
||||
5
ext/src/shim/media/classes/PauseRequest.ts
Normal file
5
ext/src/shim/media/classes/PauseRequest.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
export default class PauseRequest {
|
||||
public customData: any = null;
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
import { MetadataType } from "../enums";
|
||||
|
||||
export default class PhotoMediaMetadata {
|
||||
constructor () {
|
||||
this.artist = null;
|
||||
this.creationDateTime = null;
|
||||
this.height = null;
|
||||
this.images = null;
|
||||
this.latitude = null;
|
||||
this.location = null;
|
||||
this.longitude = null;
|
||||
this.metadataType = MetadataType.PHOTO;
|
||||
this.title = null;
|
||||
this.type = MetadataType.PHOTO;
|
||||
this.width = null;
|
||||
}
|
||||
}
|
||||
20
ext/src/shim/media/classes/PhotoMediaMetadata.ts
Normal file
20
ext/src/shim/media/classes/PhotoMediaMetadata.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
"use strict";
|
||||
|
||||
import Image from "../../cast/classes/Image";
|
||||
|
||||
import { MetadataType } from "../enums";
|
||||
|
||||
|
||||
export default class PhotoMediaMetadata {
|
||||
public artist: string = null;
|
||||
public creationDateTime: string = null;
|
||||
public height: number = null;
|
||||
public images: Image[] = null;
|
||||
public latitude: number = null;
|
||||
public location: string = null;
|
||||
public longitude: number = null;
|
||||
public metadataType: number = MetadataType.PHOTO;
|
||||
public title: string = null;
|
||||
public type: number = MetadataType.PHOTO;
|
||||
public width: number = null;
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
export default class PlayRequest {
|
||||
constructor () {
|
||||
this.customData = null;
|
||||
}
|
||||
}
|
||||
5
ext/src/shim/media/classes/PlayRequest.ts
Normal file
5
ext/src/shim/media/classes/PlayRequest.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
export default class PlayRequest {
|
||||
public customData: any = null;
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
export default class QueueInsertItemsRequest {
|
||||
constructor (itemsToInsert) {
|
||||
this.customData = null;
|
||||
this.insertBefore = null;
|
||||
this.items = itemsToInsert;
|
||||
this.requestId = null;
|
||||
this.sessionId = null;
|
||||
this.type = "QUEUE_INSERT";
|
||||
}
|
||||
}
|
||||
15
ext/src/shim/media/classes/QueueInsertItemsRequest.ts
Normal file
15
ext/src/shim/media/classes/QueueInsertItemsRequest.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
"use strict";
|
||||
|
||||
import QueueItem from "./QueueItem";
|
||||
|
||||
|
||||
export default class QueueInsertItemsRequest {
|
||||
public customData: any = null;
|
||||
public insertBefore: number = null;
|
||||
public requestId: number = null;
|
||||
public sessionId: string = null;
|
||||
public type: string = "QUEUE_INSERT";
|
||||
|
||||
constructor (
|
||||
public items: QueueItem[]) {}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
export default class QueueItem {
|
||||
constructor (mediaInfo) {
|
||||
this.activeTrackIds = null;
|
||||
this.autoplay = true;
|
||||
this.customData = null;
|
||||
this.itemId = null;
|
||||
this.media = mediaInfo;
|
||||
this.playbackDuration = null;
|
||||
this.preloadTime = 0;
|
||||
this.startTime = 0;
|
||||
}
|
||||
}
|
||||
19
ext/src/shim/media/classes/QueueItem.ts
Normal file
19
ext/src/shim/media/classes/QueueItem.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
"use strict";
|
||||
|
||||
import MediaInfo from "./MediaInfo";
|
||||
|
||||
|
||||
export default class QueueItem {
|
||||
public activeTrackIds: number[] = null;
|
||||
public autoplay: boolean = true;
|
||||
public customData: any = null;
|
||||
public itemId: number = null;
|
||||
public media: MediaInfo;
|
||||
public playbackDuration: number = null;
|
||||
public preloadTime: number = 0;
|
||||
public startTime: number = 0;
|
||||
|
||||
constructor (mediaInfo: MediaInfo) {
|
||||
this.media = mediaInfo;
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
import { RepeatMode } from "../enums";
|
||||
|
||||
export default class QueueLoadRequest {
|
||||
constructor (items) {
|
||||
this.customData = null;
|
||||
this.items = items;
|
||||
this.repeatMode = RepeatMode.OFF;
|
||||
this.requestId = null;
|
||||
this.sessionId = null;
|
||||
this.startIndex = 0;
|
||||
this.type = "QUEUE_LOAD";
|
||||
}
|
||||
}
|
||||
18
ext/src/shim/media/classes/QueueLoadRequest.ts
Normal file
18
ext/src/shim/media/classes/QueueLoadRequest.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
"use strict";
|
||||
|
||||
import QueueItem from "./QueueItem";
|
||||
|
||||
import { RepeatMode } from "../enums";
|
||||
|
||||
|
||||
export default class QueueLoadRequest {
|
||||
public customData: any = null;
|
||||
public repeatMode: string = RepeatMode.OFF;
|
||||
public requestId: number = null;
|
||||
public sessionId: string = null;
|
||||
public startIndex: number = 0;
|
||||
public type: string = "QUEUE_LOAD";
|
||||
|
||||
constructor (
|
||||
public items: QueueItem[]) {}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
export default class QueueRemoveItemsRequest {
|
||||
constructor (itemIdsToRemove) {
|
||||
this.customData = null;
|
||||
this.itemIds = itemIdsToRemove;
|
||||
this.requestId = null;
|
||||
this.sessionId = null;
|
||||
this.type = "QUEUE_REMOVE";
|
||||
}
|
||||
}
|
||||
11
ext/src/shim/media/classes/QueueRemoveItemsRequest.ts
Normal file
11
ext/src/shim/media/classes/QueueRemoveItemsRequest.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
"use strict";
|
||||
|
||||
export default class QueueRemoveItemsRequest {
|
||||
public customData: any = null;
|
||||
public requestId: number = null;
|
||||
public sessionId: string = null;
|
||||
public type: string = "QUEUE_REMOVE";
|
||||
|
||||
constructor (
|
||||
public itemIds: number[]) {}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
export default class QueueReorderItemsRequest {
|
||||
constructor (itemIdsToReorder) {
|
||||
this.customData = null;
|
||||
this.insertBefore = null;
|
||||
this.itemIds = itemIdsToReorder;
|
||||
this.requestId = null;
|
||||
this.sessionId = null;
|
||||
this.type = "QUEUE_REORDER";
|
||||
}
|
||||
}
|
||||
12
ext/src/shim/media/classes/QueueReorderItemsRequest.ts
Normal file
12
ext/src/shim/media/classes/QueueReorderItemsRequest.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
"use strict";
|
||||
|
||||
export default class QueueReorderItemsRequest {
|
||||
public customData: any = null;
|
||||
public insertBefore: number = null;
|
||||
public requestId: number = null;
|
||||
public sessionId: string = null;
|
||||
public type: string = "QUEUE_REORDER";
|
||||
|
||||
constructor (
|
||||
public itemIds: number[]) {}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
export default class QueueSetPropertiesRequest {
|
||||
constructor () {
|
||||
this.customData = null;
|
||||
this.repeatMode = null;
|
||||
this.requestId = null;
|
||||
this.sessionId = null;
|
||||
this.type = "QUEUE_UPDATE";
|
||||
}
|
||||
}
|
||||
9
ext/src/shim/media/classes/QueueSetPropertiesRequest.ts
Normal file
9
ext/src/shim/media/classes/QueueSetPropertiesRequest.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
"use strict";
|
||||
|
||||
export default class QueueSetPropertiesRequest {
|
||||
public customData: any = null;
|
||||
public repeatMode: string = null;
|
||||
public requestId: number = null;
|
||||
public sessionId: string = null;
|
||||
public type: string = "QUEUE_UPDATE";
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
export default class QueueUpdateItemsRequest {
|
||||
constructor (itemsToUpdate) {
|
||||
this.customData = null;
|
||||
this.items = itemsToUpdate;
|
||||
this.requestId = null;
|
||||
this.sessionId = null;
|
||||
this.type = "QUEUE_UPDATE";
|
||||
}
|
||||
}
|
||||
14
ext/src/shim/media/classes/QueueUpdateItemsRequest.ts
Normal file
14
ext/src/shim/media/classes/QueueUpdateItemsRequest.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
"use strict";
|
||||
|
||||
import QueueItem from "./QueueItem";
|
||||
|
||||
|
||||
export default class QueueUpdateItemsRequest {
|
||||
public customData: any = null;
|
||||
public requestId: number = null;
|
||||
public sessionId: string = null;
|
||||
public type: string = "QUEUE_UPDATE";
|
||||
|
||||
constructor (
|
||||
public items: QueueItem[]) {}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
export default class SeekRequest {
|
||||
constructor () {
|
||||
this.currentTime = null;
|
||||
this.customData = null;
|
||||
this.resumeState = null;
|
||||
}
|
||||
}
|
||||
7
ext/src/shim/media/classes/SeekRequest.ts
Normal file
7
ext/src/shim/media/classes/SeekRequest.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
"use strict";
|
||||
|
||||
export default class SeekRequest {
|
||||
public currentTime: number = null;
|
||||
public customData: any = null;
|
||||
public resumeState: string = null;
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
export default class StopRequest {
|
||||
constructor () {
|
||||
this.customData = null;
|
||||
}
|
||||
}
|
||||
5
ext/src/shim/media/classes/StopRequest.ts
Normal file
5
ext/src/shim/media/classes/StopRequest.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
export default class StopRequest {
|
||||
public customData: any = null;
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
export default class TextTrackStyle {
|
||||
constructor () {
|
||||
this.backgroundColor = null;
|
||||
this.customData = null;
|
||||
this.edgeColor = null;
|
||||
this.edgeType = null;
|
||||
this.fontFamily = null;
|
||||
this.fontGenericFamily = null;
|
||||
this.fontScale = null;
|
||||
this.fontStyle = null;
|
||||
this.foregroundColor = null;
|
||||
this.windowColor = null;
|
||||
this.windowRoundedCornerRadius = null;
|
||||
this.windowType = null;
|
||||
}
|
||||
}
|
||||
16
ext/src/shim/media/classes/TextTrackStyle.ts
Normal file
16
ext/src/shim/media/classes/TextTrackStyle.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
"use strict";
|
||||
|
||||
export default class TextTrackStyle {
|
||||
public backgroundColor: string = null;
|
||||
public customData: any = null;
|
||||
public edgeColor: string = null;
|
||||
public edgeType: string = null;
|
||||
public fontFamily: string = null;
|
||||
public fontGenericFamily: string = null;
|
||||
public fontScale: number = null;
|
||||
public fontStyle: string = null;
|
||||
public foregroundColor: string = null;
|
||||
public windowColor: string = null;
|
||||
public windowRoundedCornerRadius: number = null;
|
||||
public windowType: string = null;
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
export default class Track {
|
||||
constructor (trackId, trackType) {
|
||||
this.customData = null;
|
||||
this.language = null;
|
||||
this.name = null;
|
||||
this.subtype = null;
|
||||
this.trackContentId = null;
|
||||
this.trackContentType = null;
|
||||
this.trackId = trackId;
|
||||
this.type = trackType;
|
||||
}
|
||||
}
|
||||
14
ext/src/shim/media/classes/Track.ts
Normal file
14
ext/src/shim/media/classes/Track.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
"use strict";
|
||||
|
||||
export default class Track {
|
||||
public customData: any = null;
|
||||
public language: string = null;
|
||||
public name: string = null;
|
||||
public subtype: string = null;
|
||||
public trackContentId: string = null;
|
||||
public trackContentType: string = null;
|
||||
|
||||
constructor (
|
||||
public trackId: number
|
||||
, public type: string) {}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
import { MetadataType } from "../enums";
|
||||
|
||||
export default class TvShowMediaMetadata {
|
||||
constructor () {
|
||||
this.episode = null;
|
||||
this.episodeNumber = null;
|
||||
this.episodeTitle = null;
|
||||
this.images = null;
|
||||
this.metadataType = MetadataType.TV_SHOW;
|
||||
this.originalAirdate = null;
|
||||
this.releaseYear = null;
|
||||
this.season = null;
|
||||
this.seasonNumber = null;
|
||||
this.seriesTitle = null;
|
||||
this.title = null;
|
||||
this.type = MetadataType.TV_SHOW;
|
||||
}
|
||||
}
|
||||
21
ext/src/shim/media/classes/TvShowMediaMetadata.ts
Normal file
21
ext/src/shim/media/classes/TvShowMediaMetadata.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
"use strict";
|
||||
|
||||
import Image from "../../cast/classes/Image";
|
||||
|
||||
import { MetadataType } from "../enums";
|
||||
|
||||
|
||||
export default class TvShowMediaMetadata {
|
||||
public episode: number = null;
|
||||
public episodeNumber: number = null;
|
||||
public episodeTitle: string = null;
|
||||
public images: Image[] = null;
|
||||
public metadataType: number = MetadataType.TV_SHOW;
|
||||
public originalAirdate: string = null;
|
||||
public releaseYear: number = null;
|
||||
public season: number = null;
|
||||
public seasonNumber: number = null;
|
||||
public seriesTitle: string = null;
|
||||
public title: string = null;
|
||||
public type: number = MetadataType.TV_SHOW;
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
export default class VolumeRequest {
|
||||
constructor (volume) {
|
||||
this.customData = null;
|
||||
this.volume = volume;
|
||||
}
|
||||
}
|
||||
11
ext/src/shim/media/classes/VolumeRequest.ts
Normal file
11
ext/src/shim/media/classes/VolumeRequest.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
"use strict";
|
||||
|
||||
import Volume from "../../cast/classes/Volume";
|
||||
|
||||
|
||||
export default class VolumeRequest {
|
||||
public customData: any = null;
|
||||
|
||||
constructor (
|
||||
public volume: Volume) {}
|
||||
}
|
||||
@@ -1,93 +1,93 @@
|
||||
"use strict";
|
||||
|
||||
export const IdleReason = {
|
||||
CANCELLED: "CANCELLED"
|
||||
, INTERRUPTED: "INTERRUPTED"
|
||||
, FINISHED: "FINISHED"
|
||||
, ERROR: "ERROR"
|
||||
};
|
||||
|
||||
export const MediaCommand = {
|
||||
PAUSE: "pause"
|
||||
, SEEK: "seek"
|
||||
, STREAM_VOLUME: "stream_volume"
|
||||
, STREAM_MUTE: "stream_mute"
|
||||
};
|
||||
|
||||
export const MetadataType = {
|
||||
GENERIC: 0
|
||||
, MOVIE: 1
|
||||
, TV_SHOW: 2
|
||||
, MUSIC_TRACK: 3
|
||||
, PHOTO: 4
|
||||
};
|
||||
|
||||
export const PlayerState = {
|
||||
IDLE: "IDLE"
|
||||
, PLAYING: "PLAYING"
|
||||
, PAUSED: "PAUSED"
|
||||
, BUFFERING: "BUFFERING"
|
||||
};
|
||||
|
||||
export const RepeatMode = {
|
||||
OFF: "REPEAT_OFF"
|
||||
, ALL: "REPEAT_ALL"
|
||||
, SINGLE: "REPEAT_SINGLE"
|
||||
, ALL_AND_SHUFFLE: "REPEAT_ALL_AND_SHUFFLE"
|
||||
};
|
||||
|
||||
export const ResumeState = {
|
||||
PLAYBACK_START: "PLAYBACK_START"
|
||||
, PLAYBACK_PAUSE: "PLAYBACK_PAUSE"
|
||||
};
|
||||
|
||||
export const StreamType = {
|
||||
BUFFERED: "BUFFERED"
|
||||
, LIVE: "LIVE"
|
||||
, OTHER: "OTHER"
|
||||
};
|
||||
|
||||
export const TextTrackEdgeType = {
|
||||
NONE: "NONE"
|
||||
, OUTLINE: "OUTLINE"
|
||||
, DROP_SHADOW: "DROP_SHADOW"
|
||||
, RAISED: "RAISED"
|
||||
, DEPRESSED: "DEPRESSED"
|
||||
};
|
||||
|
||||
export const TextTrackFontGenericFamily = {
|
||||
SANS_SERIF: "SANS_SERIF"
|
||||
, MONOSPACED_SANS_SERIF: "MONOSPACED_SANS_SERIF"
|
||||
, SERIF: "SERIF"
|
||||
, MONOSPACED_SERIF: "MONOSPACED_SERIF"
|
||||
, CASUAL: "CASUAL"
|
||||
, CURSIVE: "CURSIVE"
|
||||
, SMALL_CAPITALS: "SMALL_CAPITALS"
|
||||
};
|
||||
|
||||
export const TextTrackFontStyle = {
|
||||
NORMAL: "NORMAL"
|
||||
, BOLD: "BOLD"
|
||||
, BOLD_ITALIC: "BOLD_ITALIC"
|
||||
, ITALIC: "ITALIC"
|
||||
};
|
||||
|
||||
export const TextTrackType = {
|
||||
SUBTITLES: "SUBTITLES"
|
||||
, CAPTIONS: "CAPTIONS"
|
||||
, DESCRIPTIONS: "DESCRIPTIONS"
|
||||
, CHAPTERS: "CHAPTERS"
|
||||
, METADATA: "METADATA"
|
||||
};
|
||||
|
||||
export const TextTrackWindowType = {
|
||||
NONE: "NONE"
|
||||
, NORMAL: "NORMAL"
|
||||
, ROUNDED_CORNERS: "ROUNDED_CORNERS"
|
||||
};
|
||||
|
||||
export const TrackType = {
|
||||
TEXT: "TEXT"
|
||||
, AUDIO: "AUDIO"
|
||||
, VIDEO: "VIDEO"
|
||||
};
|
||||
"use strict";
|
||||
|
||||
export const IdleReason = {
|
||||
CANCELLED: "CANCELLED"
|
||||
, INTERRUPTED: "INTERRUPTED"
|
||||
, FINISHED: "FINISHED"
|
||||
, ERROR: "ERROR"
|
||||
};
|
||||
|
||||
export const MediaCommand = {
|
||||
PAUSE: "pause"
|
||||
, SEEK: "seek"
|
||||
, STREAM_VOLUME: "stream_volume"
|
||||
, STREAM_MUTE: "stream_mute"
|
||||
};
|
||||
|
||||
export const MetadataType = {
|
||||
GENERIC: 0
|
||||
, MOVIE: 1
|
||||
, TV_SHOW: 2
|
||||
, MUSIC_TRACK: 3
|
||||
, PHOTO: 4
|
||||
};
|
||||
|
||||
export const PlayerState = {
|
||||
IDLE: "IDLE"
|
||||
, PLAYING: "PLAYING"
|
||||
, PAUSED: "PAUSED"
|
||||
, BUFFERING: "BUFFERING"
|
||||
};
|
||||
|
||||
export const RepeatMode = {
|
||||
OFF: "REPEAT_OFF"
|
||||
, ALL: "REPEAT_ALL"
|
||||
, SINGLE: "REPEAT_SINGLE"
|
||||
, ALL_AND_SHUFFLE: "REPEAT_ALL_AND_SHUFFLE"
|
||||
};
|
||||
|
||||
export const ResumeState = {
|
||||
PLAYBACK_START: "PLAYBACK_START"
|
||||
, PLAYBACK_PAUSE: "PLAYBACK_PAUSE"
|
||||
};
|
||||
|
||||
export const StreamType = {
|
||||
BUFFERED: "BUFFERED"
|
||||
, LIVE: "LIVE"
|
||||
, OTHER: "OTHER"
|
||||
};
|
||||
|
||||
export const TextTrackEdgeType = {
|
||||
NONE: "NONE"
|
||||
, OUTLINE: "OUTLINE"
|
||||
, DROP_SHADOW: "DROP_SHADOW"
|
||||
, RAISED: "RAISED"
|
||||
, DEPRESSED: "DEPRESSED"
|
||||
};
|
||||
|
||||
export const TextTrackFontGenericFamily = {
|
||||
SANS_SERIF: "SANS_SERIF"
|
||||
, MONOSPACED_SANS_SERIF: "MONOSPACED_SANS_SERIF"
|
||||
, SERIF: "SERIF"
|
||||
, MONOSPACED_SERIF: "MONOSPACED_SERIF"
|
||||
, CASUAL: "CASUAL"
|
||||
, CURSIVE: "CURSIVE"
|
||||
, SMALL_CAPITALS: "SMALL_CAPITALS"
|
||||
};
|
||||
|
||||
export const TextTrackFontStyle = {
|
||||
NORMAL: "NORMAL"
|
||||
, BOLD: "BOLD"
|
||||
, BOLD_ITALIC: "BOLD_ITALIC"
|
||||
, ITALIC: "ITALIC"
|
||||
};
|
||||
|
||||
export const TextTrackType = {
|
||||
SUBTITLES: "SUBTITLES"
|
||||
, CAPTIONS: "CAPTIONS"
|
||||
, DESCRIPTIONS: "DESCRIPTIONS"
|
||||
, CHAPTERS: "CHAPTERS"
|
||||
, METADATA: "METADATA"
|
||||
};
|
||||
|
||||
export const TextTrackWindowType = {
|
||||
NONE: "NONE"
|
||||
, NORMAL: "NORMAL"
|
||||
, ROUNDED_CORNERS: "ROUNDED_CORNERS"
|
||||
};
|
||||
|
||||
export const TrackType = {
|
||||
TEXT: "TEXT"
|
||||
, AUDIO: "AUDIO"
|
||||
, VIDEO: "VIDEO"
|
||||
};
|
||||
@@ -1,98 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
import EditTracksInfoRequest from "./classes/EditTracksInfoRequest";
|
||||
import GenericMediaMetadata from "./classes/GenericMediaMetadata";
|
||||
import GetStatusRequest from "./classes/GetStatusRequest";
|
||||
import LoadRequest from "./classes/LoadRequest";
|
||||
import Media from "./classes/Media";
|
||||
import MediaInfo from "./classes/MediaInfo";
|
||||
import MovieMediaMetadata from "./classes/MovieMediaMetadata";
|
||||
import MusicTrackMediaMetadata from "./classes/MusicTrackMediaMetadata";
|
||||
import PauseRequest from "./classes/PauseRequest";
|
||||
import PhotoMediaMetadata from "./classes/PhotoMediaMetadata";
|
||||
import PlayRequest from "./classes/PlayRequest";
|
||||
import QueueInsertItemsRequest from "./classes/QueueInsertItemsRequest";
|
||||
import QueueItem from "./classes/QueueItem";
|
||||
import QueueLoadRequest from "./classes/QueueLoadRequest";
|
||||
import QueueRemoveItemsRequest from "./classes/QueueRemoveItemsRequest";
|
||||
import QueueReorderItemsRequest from "./classes/QueueReorderItemsRequest";
|
||||
import QueueSetPropertiesRequest from "./classes/QueueSetPropertiesRequest";
|
||||
import QueueUpdateItemsRequest from "./classes/QueueUpdateItemsRequest";
|
||||
import SeekRequest from "./classes/SeekRequest";
|
||||
import StopRequest from "./classes/StopRequest";
|
||||
import TextTrackStyle from "./classes/TextTrackStyle";
|
||||
import Track from "./classes/Track";
|
||||
import TvShowMediaMetadata from "./classes/TvShowMediaMetadata";
|
||||
import VolumeRequest from "./classes/VolumeRequest";
|
||||
|
||||
import { IdleReason
|
||||
, MediaCommand
|
||||
, MetadataType
|
||||
, PlayerState
|
||||
, RepeatMode
|
||||
, ResumeState
|
||||
, StreamType
|
||||
, TextTrackEdgeType
|
||||
, TextTrackFontGenericFamily
|
||||
, TextTrackFontStyle
|
||||
, TextTrackType
|
||||
, TextTrackWindowType
|
||||
, TrackType } from "./enums";
|
||||
|
||||
|
||||
export default {
|
||||
// Enums
|
||||
IdleReason
|
||||
, MediaCommand
|
||||
, MetadataType
|
||||
, PlayerState
|
||||
, RepeatMode
|
||||
, ResumeState
|
||||
, StreamType
|
||||
, TextTrackEdgeType
|
||||
, TextTrackFontGenericFamily
|
||||
, TextTrackFontStyle
|
||||
, TextTrackType
|
||||
, TextTrackWindowType
|
||||
, TrackType
|
||||
|
||||
// Classes
|
||||
, EditTracksInfoRequest
|
||||
, GenericMediaMetadata
|
||||
, GetStatusRequest
|
||||
, LoadRequest
|
||||
, Media
|
||||
, MediaInfo
|
||||
, MovieMediaMetadata
|
||||
, MusicTrackMediaMetadata
|
||||
, PauseRequest
|
||||
, PhotoMediaMetadata
|
||||
, PlayRequest
|
||||
, QueueInsertItemsRequest
|
||||
, QueueItem
|
||||
, QueueLoadRequest
|
||||
, QueueRemoveItemsRequest
|
||||
, QueueReorderItemsRequest
|
||||
, QueueSetPropertiesRequest
|
||||
, QueueUpdateItemsRequest
|
||||
, SeekRequest
|
||||
, StopRequest
|
||||
, TextTrackStyle
|
||||
, Track
|
||||
, TvShowMediaMetadata
|
||||
, VolumeRequest
|
||||
|
||||
, timeout: {
|
||||
editTracksInfo: 0
|
||||
, getStatus: 0
|
||||
, load: 0
|
||||
, pause: 0
|
||||
, play: 0
|
||||
, queue: 0
|
||||
, seek: 0
|
||||
, setVolume: 0
|
||||
, stop: 0
|
||||
}
|
||||
|
||||
, DEFAULT_MEDIA_RECEIVER_APP_ID: "CC1AD845"
|
||||
};
|
||||
98
ext/src/shim/media/index.ts
Executable file
98
ext/src/shim/media/index.ts
Executable file
@@ -0,0 +1,98 @@
|
||||
"use strict";
|
||||
|
||||
import EditTracksInfoRequest from "./classes/EditTracksInfoRequest";
|
||||
import GenericMediaMetadata from "./classes/GenericMediaMetadata";
|
||||
import GetStatusRequest from "./classes/GetStatusRequest";
|
||||
import LoadRequest from "./classes/LoadRequest";
|
||||
import Media from "./classes/Media";
|
||||
import MediaInfo from "./classes/MediaInfo";
|
||||
import MovieMediaMetadata from "./classes/MovieMediaMetadata";
|
||||
import MusicTrackMediaMetadata from "./classes/MusicTrackMediaMetadata";
|
||||
import PauseRequest from "./classes/PauseRequest";
|
||||
import PhotoMediaMetadata from "./classes/PhotoMediaMetadata";
|
||||
import PlayRequest from "./classes/PlayRequest";
|
||||
import QueueInsertItemsRequest from "./classes/QueueInsertItemsRequest";
|
||||
import QueueItem from "./classes/QueueItem";
|
||||
import QueueLoadRequest from "./classes/QueueLoadRequest";
|
||||
import QueueRemoveItemsRequest from "./classes/QueueRemoveItemsRequest";
|
||||
import QueueReorderItemsRequest from "./classes/QueueReorderItemsRequest";
|
||||
import QueueSetPropertiesRequest from "./classes/QueueSetPropertiesRequest";
|
||||
import QueueUpdateItemsRequest from "./classes/QueueUpdateItemsRequest";
|
||||
import SeekRequest from "./classes/SeekRequest";
|
||||
import StopRequest from "./classes/StopRequest";
|
||||
import TextTrackStyle from "./classes/TextTrackStyle";
|
||||
import Track from "./classes/Track";
|
||||
import TvShowMediaMetadata from "./classes/TvShowMediaMetadata";
|
||||
import VolumeRequest from "./classes/VolumeRequest";
|
||||
|
||||
import { IdleReason
|
||||
, MediaCommand
|
||||
, MetadataType
|
||||
, PlayerState
|
||||
, RepeatMode
|
||||
, ResumeState
|
||||
, StreamType
|
||||
, TextTrackEdgeType
|
||||
, TextTrackFontGenericFamily
|
||||
, TextTrackFontStyle
|
||||
, TextTrackType
|
||||
, TextTrackWindowType
|
||||
, TrackType } from "./enums";
|
||||
|
||||
|
||||
export default {
|
||||
// Enums
|
||||
IdleReason
|
||||
, MediaCommand
|
||||
, MetadataType
|
||||
, PlayerState
|
||||
, RepeatMode
|
||||
, ResumeState
|
||||
, StreamType
|
||||
, TextTrackEdgeType
|
||||
, TextTrackFontGenericFamily
|
||||
, TextTrackFontStyle
|
||||
, TextTrackType
|
||||
, TextTrackWindowType
|
||||
, TrackType
|
||||
|
||||
// Classes
|
||||
, EditTracksInfoRequest
|
||||
, GenericMediaMetadata
|
||||
, GetStatusRequest
|
||||
, LoadRequest
|
||||
, Media
|
||||
, MediaInfo
|
||||
, MovieMediaMetadata
|
||||
, MusicTrackMediaMetadata
|
||||
, PauseRequest
|
||||
, PhotoMediaMetadata
|
||||
, PlayRequest
|
||||
, QueueInsertItemsRequest
|
||||
, QueueItem
|
||||
, QueueLoadRequest
|
||||
, QueueRemoveItemsRequest
|
||||
, QueueReorderItemsRequest
|
||||
, QueueSetPropertiesRequest
|
||||
, QueueUpdateItemsRequest
|
||||
, SeekRequest
|
||||
, StopRequest
|
||||
, TextTrackStyle
|
||||
, Track
|
||||
, TvShowMediaMetadata
|
||||
, VolumeRequest
|
||||
|
||||
, timeout: {
|
||||
editTracksInfo: 0
|
||||
, getStatus: 0
|
||||
, load: 0
|
||||
, pause: 0
|
||||
, play: 0
|
||||
, queue: 0
|
||||
, seek: 0
|
||||
, setVolume: 0
|
||||
, stop: 0
|
||||
}
|
||||
|
||||
, DEFAULT_MEDIA_RECEIVER_APP_ID: "CC1AD845"
|
||||
};
|
||||
@@ -1,7 +1,12 @@
|
||||
"use strict";
|
||||
|
||||
export function onMessage (listener) {
|
||||
document.addEventListener("__castMessage", ev => {
|
||||
import { Message } from "../types";
|
||||
|
||||
type ListenerFunc = (message: Message) => void;
|
||||
|
||||
|
||||
export function onMessage (listener: ListenerFunc) {
|
||||
document.addEventListener("__castMessage", (ev: CustomEvent) => {
|
||||
listener(JSON.parse(ev.detail));
|
||||
|
||||
/**
|
||||
@@ -16,7 +21,7 @@ export function onMessage (listener) {
|
||||
}, true);
|
||||
}
|
||||
|
||||
export function sendMessageResponse (message) {
|
||||
export function sendMessageResponse (message: Message) {
|
||||
const event = new CustomEvent("__castMessageResponse", {
|
||||
detail: JSON.stringify(message)
|
||||
});
|
||||
@@ -25,13 +30,13 @@ export function sendMessageResponse (message) {
|
||||
}
|
||||
|
||||
|
||||
export function onMessageResponse (listener) {
|
||||
document.addEventListener("__castMessageResponse", ev => {
|
||||
export function onMessageResponse (listener: ListenerFunc) {
|
||||
document.addEventListener("__castMessageResponse", (ev: CustomEvent) => {
|
||||
listener(JSON.parse(ev.detail));
|
||||
}, true);
|
||||
}
|
||||
|
||||
export function sendMessage (message) {
|
||||
export function sendMessage (message: Message) {
|
||||
const event = new CustomEvent("__castMessage", {
|
||||
detail: JSON.stringify(message)
|
||||
});
|
||||
@@ -1,11 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
// Global API state
|
||||
const state = {
|
||||
apiConfig: null
|
||||
, receiverList: []
|
||||
, sessionList: []
|
||||
, sessionRequestInProgress: false
|
||||
};
|
||||
|
||||
export default state;
|
||||
22
ext/src/shim/state.ts
Executable file
22
ext/src/shim/state.ts
Executable file
@@ -0,0 +1,22 @@
|
||||
"use strict";
|
||||
|
||||
import ApiConfig from "./cast/classes/ApiConfig";
|
||||
import Receiver from "./cast/classes/Receiver";
|
||||
import Session from "./cast/classes/Session";
|
||||
|
||||
export interface State {
|
||||
apiConfig: ApiConfig;
|
||||
receiverList: Receiver[];
|
||||
sessionList: Session[];
|
||||
sessionRequestInProgress: boolean;
|
||||
}
|
||||
|
||||
// Global API state
|
||||
const state: State = {
|
||||
apiConfig: null
|
||||
, receiverList: []
|
||||
, sessionList: []
|
||||
, sessionRequestInProgress: false
|
||||
};
|
||||
|
||||
export default state;
|
||||
@@ -1,7 +1,7 @@
|
||||
"use strict";
|
||||
|
||||
export const leaveSession = 3000;
|
||||
export const requestSession = 60000;
|
||||
export const sendCustomMessage = 3000;
|
||||
export const setReceiverVolume = 3000;
|
||||
export const stopSession = 3000;
|
||||
"use strict";
|
||||
|
||||
export const leaveSession = 3000;
|
||||
export const requestSession = 60000;
|
||||
export const sendCustomMessage = 3000;
|
||||
export const setReceiverVolume = 3000;
|
||||
export const stopSession = 3000;
|
||||
15
ext/src/shim/types.ts
Normal file
15
ext/src/shim/types.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
"use strict";
|
||||
|
||||
import _Error from "./cast/classes/Error";
|
||||
import Media from "./media/classes/Media";
|
||||
|
||||
export type SuccessCallback = () => void;
|
||||
export type ErrorCallback = (err: _Error) => void;
|
||||
|
||||
export type MediaListener = (media: Media) => void;
|
||||
export type MessageListener = (namespace: string, message: string) => void;
|
||||
export type UpdateListener = (isAlive: boolean) => void;
|
||||
export type LoadSuccessCallback = (media: Media) => void;
|
||||
|
||||
export type Callbacks = [ SuccessCallback, ErrorCallback ];
|
||||
export type CallbacksMap = Map<string, Callbacks>;
|
||||
@@ -2,7 +2,8 @@
|
||||
|
||||
export interface Message {
|
||||
subject: string;
|
||||
data: any;
|
||||
data?: any;
|
||||
_id?: string;
|
||||
}
|
||||
|
||||
export interface Receiver {
|
||||
|
||||
@@ -15,9 +15,9 @@ module.exports = (env) => ({
|
||||
, "compat/youtube" : `${env.includePath}/compat/youtube.js`
|
||||
|
||||
// Shim entries
|
||||
, "shim/bundle" : `${env.includePath}/shim/index.js`
|
||||
, "shim/content" : `${env.includePath}/shim/content.js`
|
||||
, "shim/contentSetup" : `${env.includePath}/shim/contentSetup.js`
|
||||
, "shim/bundle" : `${env.includePath}/shim/index.ts`
|
||||
, "shim/content" : `${env.includePath}/shim/content.ts`
|
||||
, "shim/contentSetup" : `${env.includePath}/shim/contentSetup.ts`
|
||||
}
|
||||
, output: {
|
||||
filename: "[name].js"
|
||||
@@ -38,7 +38,8 @@ module.exports = (env) => ({
|
||||
{
|
||||
from: env.includePath
|
||||
, to: env.outputPath
|
||||
, ignore: [ "*.js", "*.jsx" ]
|
||||
, ignore: [ "*.js", "*.jsx"
|
||||
, "*.ts", "*.tsx" ]
|
||||
, transform (content, path) {
|
||||
// Access to variables in static files
|
||||
if (path.endsWith(".json")) {
|
||||
|
||||
6
package-lock.json
generated
6
package-lock.json
generated
@@ -8,6 +8,12 @@
|
||||
"integrity": "sha512-vVjM0SVzgaOUpflq4GYBvCpozes8OgIIS5gVXVka+OfK3hvnkC1i93U8WiY2OtNE4XUWyyy/86Kf6e0IHTQw1Q==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/semver": {
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-5.5.0.tgz",
|
||||
"integrity": "sha512-41qEJgBH/TWgo5NFSvBCJ1qkoi3Q6ONSF2avrHq1LVEZfYpdHmj0y9SuTK+u9ZhG1sYQKBL1AWXKyLWP4RaUoQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/uuid": {
|
||||
"version": "3.4.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-3.4.4.tgz",
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
"lint:ext": "npm run lint --prefix ./ext"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/semver": "^5.5.0",
|
||||
"@types/uuid": "^3.4.4",
|
||||
"fs-extra": "^7.0.1",
|
||||
"glob": "^7.1.3",
|
||||
|
||||
@@ -20,8 +20,8 @@ const { __extensionName
|
||||
, __extensionVersion } = require("../ext/package.json");
|
||||
|
||||
const extensionArchivePath = path.join(
|
||||
path.join(__dirname, "../dist/ext/")
|
||||
, `${__extensionName}-${__extensionVersion}.xpi`);
|
||||
__dirname, "../dist/ext"
|
||||
, `${__extensionName}-${__extensionVersion}.xpi`)
|
||||
|
||||
if (!fs.existsSync(extensionArchivePath)) {
|
||||
console.error("Extension archive not found.");
|
||||
|
||||
Reference in New Issue
Block a user