From f1125061d5ea2989e5f7c2d6eefe00dc4437a1eb Mon Sep 17 00:00:00 2001 From: Matt Hensman Date: Tue, 12 Mar 2019 05:51:43 +0000 Subject: [PATCH] Convert shim to Typescript (#32) --- ext/package-lock.json | 43 ++- ext/src/global.d.ts | 31 ++ ext/src/manifest.json | 2 +- ext/src/shim/cast/classes/ApiConfig.js | 28 -- ext/src/shim/cast/classes/ApiConfig.ts | 25 ++ .../{DialRequest.js => DialRequest.ts} | 21 +- ext/src/shim/cast/classes/Error.js | 14 - ext/src/shim/cast/classes/Error.ts | 10 + .../shim/cast/classes/{Image.js => Image.ts} | 20 +- ext/src/shim/cast/classes/Receiver.js | 22 -- ext/src/shim/cast/classes/Receiver.ts | 21 ++ .../cast/classes/ReceiverDisplayStatus.js | 10 - .../cast/classes/ReceiverDisplayStatus.ts | 13 + ...derApplication.js => SenderApplication.ts} | 19 +- .../cast/classes/{Session.js => Session.ts} | 203 ++++++++---- ext/src/shim/cast/classes/SessionRequest.js | 21 -- ext/src/shim/cast/classes/SessionRequest.ts | 17 + .../cast/classes/{Timeout.js => Timeout.ts} | 20 +- .../cast/classes/{Volume.js => Volume.ts} | 28 +- ext/src/shim/cast/classes/index.js | 28 -- .../shim/cast/enums/{index.js => index.ts} | 150 ++++----- ext/src/shim/cast/index.js | 285 ---------------- ext/src/shim/cast/index.ts | 288 ++++++++++++++++ ext/src/shim/content.js | 34 -- ext/src/shim/content.ts | 34 ++ ext/src/shim/contentSetup.js | 3 - ext/src/shim/contentSetup.ts | 3 + ext/src/shim/{index.js => index.ts} | 17 +- .../media/classes/EditTracksInfoRequest.js | 9 - .../media/classes/EditTracksInfoRequest.ts | 10 + .../media/classes/GenericMediaMetadata.js | 15 - .../media/classes/GenericMediaMetadata.ts | 16 + .../shim/media/classes/GetStatusRequest.js | 7 - .../shim/media/classes/GetStatusRequest.ts | 5 + ext/src/shim/media/classes/LoadRequest.js | 14 - ext/src/shim/media/classes/LoadRequest.ts | 19 ++ ext/src/shim/media/classes/Media.js | 197 ----------- ext/src/shim/media/classes/Media.ts | 311 ++++++++++++++++++ ext/src/shim/media/classes/MediaInfo.js | 16 - ext/src/shim/media/classes/MediaInfo.ts | 33 ++ .../shim/media/classes/MovieMediaMetadata.js | 16 - .../shim/media/classes/MovieMediaMetadata.ts | 17 + .../media/classes/MusicTrackMediaMetadata.js | 22 -- .../media/classes/MusicTrackMediaMetadata.ts | 23 ++ ext/src/shim/media/classes/PauseRequest.js | 7 - ext/src/shim/media/classes/PauseRequest.ts | 5 + .../shim/media/classes/PhotoMediaMetadata.js | 19 -- .../shim/media/classes/PhotoMediaMetadata.ts | 20 ++ ext/src/shim/media/classes/PlayRequest.js | 7 - ext/src/shim/media/classes/PlayRequest.ts | 5 + .../media/classes/QueueInsertItemsRequest.js | 12 - .../media/classes/QueueInsertItemsRequest.ts | 15 + ext/src/shim/media/classes/QueueItem.js | 14 - ext/src/shim/media/classes/QueueItem.ts | 19 ++ .../shim/media/classes/QueueLoadRequest.js | 15 - .../shim/media/classes/QueueLoadRequest.ts | 18 + .../media/classes/QueueRemoveItemsRequest.js | 11 - .../media/classes/QueueRemoveItemsRequest.ts | 11 + .../media/classes/QueueReorderItemsRequest.js | 12 - .../media/classes/QueueReorderItemsRequest.ts | 12 + .../classes/QueueSetPropertiesRequest.js | 11 - .../classes/QueueSetPropertiesRequest.ts | 9 + .../media/classes/QueueUpdateItemsRequest.js | 11 - .../media/classes/QueueUpdateItemsRequest.ts | 14 + ext/src/shim/media/classes/SeekRequest.js | 9 - ext/src/shim/media/classes/SeekRequest.ts | 7 + ext/src/shim/media/classes/StopRequest.js | 7 - ext/src/shim/media/classes/StopRequest.ts | 5 + ext/src/shim/media/classes/TextTrackStyle.js | 18 - ext/src/shim/media/classes/TextTrackStyle.ts | 16 + ext/src/shim/media/classes/Track.js | 14 - ext/src/shim/media/classes/Track.ts | 14 + .../shim/media/classes/TvShowMediaMetadata.js | 20 -- .../shim/media/classes/TvShowMediaMetadata.ts | 21 ++ ext/src/shim/media/classes/VolumeRequest.js | 8 - ext/src/shim/media/classes/VolumeRequest.ts | 11 + .../shim/media/enums/{index.js => index.ts} | 186 +++++------ ext/src/shim/media/index.js | 98 ------ ext/src/shim/media/index.ts | 98 ++++++ .../{messageBridge.js => messageBridge.ts} | 17 +- ext/src/shim/state.js | 11 - ext/src/shim/state.ts | 22 ++ ext/src/shim/{timeout.js => timeout.ts} | 14 +- ext/src/shim/types.ts | 15 + ext/src/types.ts | 3 +- ext/webpack.config.js | 9 +- package-lock.json | 6 + package.json | 1 + test/driver.js | 4 +- 89 files changed, 1643 insertions(+), 1378 deletions(-) delete mode 100755 ext/src/shim/cast/classes/ApiConfig.js create mode 100755 ext/src/shim/cast/classes/ApiConfig.ts rename ext/src/shim/cast/classes/{DialRequest.js => DialRequest.ts} (50%) delete mode 100755 ext/src/shim/cast/classes/Error.js create mode 100755 ext/src/shim/cast/classes/Error.ts rename ext/src/shim/cast/classes/{Image.js => Image.ts} (54%) delete mode 100755 ext/src/shim/cast/classes/Receiver.js create mode 100755 ext/src/shim/cast/classes/Receiver.ts delete mode 100755 ext/src/shim/cast/classes/ReceiverDisplayStatus.js create mode 100755 ext/src/shim/cast/classes/ReceiverDisplayStatus.ts rename ext/src/shim/cast/classes/{SenderApplication.js => SenderApplication.ts} (52%) rename ext/src/shim/cast/classes/{Session.js => Session.ts} (64%) delete mode 100755 ext/src/shim/cast/classes/SessionRequest.js create mode 100755 ext/src/shim/cast/classes/SessionRequest.ts rename ext/src/shim/cast/classes/{Timeout.js => Timeout.ts} (77%) rename ext/src/shim/cast/classes/{Volume.js => Volume.ts} (56%) delete mode 100755 ext/src/shim/cast/classes/index.js rename ext/src/shim/cast/enums/{index.js => index.ts} (95%) delete mode 100755 ext/src/shim/cast/index.js create mode 100755 ext/src/shim/cast/index.ts delete mode 100644 ext/src/shim/content.js create mode 100644 ext/src/shim/content.ts delete mode 100644 ext/src/shim/contentSetup.js create mode 100644 ext/src/shim/contentSetup.ts rename ext/src/shim/{index.js => index.ts} (66%) delete mode 100644 ext/src/shim/media/classes/EditTracksInfoRequest.js create mode 100644 ext/src/shim/media/classes/EditTracksInfoRequest.ts delete mode 100644 ext/src/shim/media/classes/GenericMediaMetadata.js create mode 100644 ext/src/shim/media/classes/GenericMediaMetadata.ts delete mode 100644 ext/src/shim/media/classes/GetStatusRequest.js create mode 100644 ext/src/shim/media/classes/GetStatusRequest.ts delete mode 100644 ext/src/shim/media/classes/LoadRequest.js create mode 100644 ext/src/shim/media/classes/LoadRequest.ts delete mode 100644 ext/src/shim/media/classes/Media.js create mode 100644 ext/src/shim/media/classes/Media.ts delete mode 100644 ext/src/shim/media/classes/MediaInfo.js create mode 100644 ext/src/shim/media/classes/MediaInfo.ts delete mode 100644 ext/src/shim/media/classes/MovieMediaMetadata.js create mode 100644 ext/src/shim/media/classes/MovieMediaMetadata.ts delete mode 100644 ext/src/shim/media/classes/MusicTrackMediaMetadata.js create mode 100644 ext/src/shim/media/classes/MusicTrackMediaMetadata.ts delete mode 100644 ext/src/shim/media/classes/PauseRequest.js create mode 100644 ext/src/shim/media/classes/PauseRequest.ts delete mode 100644 ext/src/shim/media/classes/PhotoMediaMetadata.js create mode 100644 ext/src/shim/media/classes/PhotoMediaMetadata.ts delete mode 100644 ext/src/shim/media/classes/PlayRequest.js create mode 100644 ext/src/shim/media/classes/PlayRequest.ts delete mode 100644 ext/src/shim/media/classes/QueueInsertItemsRequest.js create mode 100644 ext/src/shim/media/classes/QueueInsertItemsRequest.ts delete mode 100644 ext/src/shim/media/classes/QueueItem.js create mode 100644 ext/src/shim/media/classes/QueueItem.ts delete mode 100644 ext/src/shim/media/classes/QueueLoadRequest.js create mode 100644 ext/src/shim/media/classes/QueueLoadRequest.ts delete mode 100644 ext/src/shim/media/classes/QueueRemoveItemsRequest.js create mode 100644 ext/src/shim/media/classes/QueueRemoveItemsRequest.ts delete mode 100644 ext/src/shim/media/classes/QueueReorderItemsRequest.js create mode 100644 ext/src/shim/media/classes/QueueReorderItemsRequest.ts delete mode 100644 ext/src/shim/media/classes/QueueSetPropertiesRequest.js create mode 100644 ext/src/shim/media/classes/QueueSetPropertiesRequest.ts delete mode 100644 ext/src/shim/media/classes/QueueUpdateItemsRequest.js create mode 100644 ext/src/shim/media/classes/QueueUpdateItemsRequest.ts delete mode 100644 ext/src/shim/media/classes/SeekRequest.js create mode 100644 ext/src/shim/media/classes/SeekRequest.ts delete mode 100644 ext/src/shim/media/classes/StopRequest.js create mode 100644 ext/src/shim/media/classes/StopRequest.ts delete mode 100644 ext/src/shim/media/classes/TextTrackStyle.js create mode 100644 ext/src/shim/media/classes/TextTrackStyle.ts delete mode 100644 ext/src/shim/media/classes/Track.js create mode 100644 ext/src/shim/media/classes/Track.ts delete mode 100644 ext/src/shim/media/classes/TvShowMediaMetadata.js create mode 100644 ext/src/shim/media/classes/TvShowMediaMetadata.ts delete mode 100644 ext/src/shim/media/classes/VolumeRequest.js create mode 100644 ext/src/shim/media/classes/VolumeRequest.ts rename ext/src/shim/media/enums/{index.js => index.ts} (95%) delete mode 100755 ext/src/shim/media/index.js create mode 100755 ext/src/shim/media/index.ts rename ext/src/shim/{messageBridge.js => messageBridge.ts} (63%) delete mode 100755 ext/src/shim/state.js create mode 100755 ext/src/shim/state.ts rename ext/src/shim/{timeout.js => timeout.ts} (96%) create mode 100644 ext/src/shim/types.ts diff --git a/ext/package-lock.json b/ext/package-lock.json index aa0d6a3..2783726 100644 --- a/ext/package-lock.json +++ b/ext/package-lock.json @@ -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 }, diff --git a/ext/src/global.d.ts b/ext/src/global.d.ts index d579c2f..48b21c1 100644 --- a/ext/src/global.d.ts +++ b/ext/src/global.d.ts @@ -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 ( + 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 { /** diff --git a/ext/src/manifest.json b/ext/src/manifest.json index 54b62f9..4b75006 100755 --- a/ext/src/manifest.json +++ b/ext/src/manifest.json @@ -3,7 +3,7 @@ , "description": "__MSG_extensionDescription__" , "version": "EXTENSION_VERSION" - , "browser_specific_settings": { + , "applications": { "gecko": { "id": "EXTENSION_ID" , "strict_min_version": "64.0" diff --git a/ext/src/shim/cast/classes/ApiConfig.js b/ext/src/shim/cast/classes/ApiConfig.js deleted file mode 100755 index 1746606..0000000 --- a/ext/src/shim/cast/classes/ApiConfig.js +++ /dev/null @@ -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; - } -}; diff --git a/ext/src/shim/cast/classes/ApiConfig.ts b/ext/src/shim/cast/classes/ApiConfig.ts new file mode 100755 index 0000000..b593be6 --- /dev/null +++ b/ext/src/shim/cast/classes/ApiConfig.ts @@ -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") { + } +}; diff --git a/ext/src/shim/cast/classes/DialRequest.js b/ext/src/shim/cast/classes/DialRequest.ts similarity index 50% rename from ext/src/shim/cast/classes/DialRequest.js rename to ext/src/shim/cast/classes/DialRequest.ts index 266e567..f3e30c2 100755 --- a/ext/src/shim/cast/classes/DialRequest.js +++ b/ext/src/shim/cast/classes/DialRequest.ts @@ -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) { + } +}; diff --git a/ext/src/shim/cast/classes/Error.js b/ext/src/shim/cast/classes/Error.js deleted file mode 100755 index a9d1fd6..0000000 --- a/ext/src/shim/cast/classes/Error.js +++ /dev/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; - } -}; diff --git a/ext/src/shim/cast/classes/Error.ts b/ext/src/shim/cast/classes/Error.ts new file mode 100755 index 0000000..ca90260 --- /dev/null +++ b/ext/src/shim/cast/classes/Error.ts @@ -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) { + } +}; diff --git a/ext/src/shim/cast/classes/Image.js b/ext/src/shim/cast/classes/Image.ts similarity index 54% rename from ext/src/shim/cast/classes/Image.js rename to ext/src/shim/cast/classes/Image.ts index a655fe6..dba1c48 100755 --- a/ext/src/shim/cast/classes/Image.js +++ b/ext/src/shim/cast/classes/Image.ts @@ -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) {} +}; diff --git a/ext/src/shim/cast/classes/Receiver.js b/ext/src/shim/cast/classes/Receiver.js deleted file mode 100755 index cfb1419..0000000 --- a/ext/src/shim/cast/classes/Receiver.js +++ /dev/null @@ -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; - } -}; diff --git a/ext/src/shim/cast/classes/Receiver.ts b/ext/src/shim/cast/classes/Receiver.ts new file mode 100755 index 0000000..516ff64 --- /dev/null +++ b/ext/src/shim/cast/classes/Receiver.ts @@ -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) { + } +}; diff --git a/ext/src/shim/cast/classes/ReceiverDisplayStatus.js b/ext/src/shim/cast/classes/ReceiverDisplayStatus.js deleted file mode 100755 index 376e0b6..0000000 --- a/ext/src/shim/cast/classes/ReceiverDisplayStatus.js +++ /dev/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; - } -}; diff --git a/ext/src/shim/cast/classes/ReceiverDisplayStatus.ts b/ext/src/shim/cast/classes/ReceiverDisplayStatus.ts new file mode 100755 index 0000000..cd4f81c --- /dev/null +++ b/ext/src/shim/cast/classes/ReceiverDisplayStatus.ts @@ -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[]) {} +}; diff --git a/ext/src/shim/cast/classes/SenderApplication.js b/ext/src/shim/cast/classes/SenderApplication.ts similarity index 52% rename from ext/src/shim/cast/classes/SenderApplication.js rename to ext/src/shim/cast/classes/SenderApplication.ts index cb0d43c..6f74fde 100755 --- a/ext/src/shim/cast/classes/SenderApplication.js +++ b/ext/src/shim/cast/classes/SenderApplication.ts @@ -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) {} +}; diff --git a/ext/src/shim/cast/classes/Session.js b/ext/src/shim/cast/classes/Session.ts similarity index 64% rename from ext/src/shim/cast/classes/Session.js rename to ext/src/shim/cast/classes/Session.ts index 7bb6ce4..cf945de 100755 --- a/ext/src/shim/cast/classes/Session.js +++ b/ext/src/shim/cast/classes/Session.ts @@ -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>(); + private _updateListeners = new Set(); + + 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); + } } diff --git a/ext/src/shim/cast/classes/SessionRequest.js b/ext/src/shim/cast/classes/SessionRequest.js deleted file mode 100755 index f9ce68b..0000000 --- a/ext/src/shim/cast/classes/SessionRequest.js +++ /dev/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; - } -}; diff --git a/ext/src/shim/cast/classes/SessionRequest.ts b/ext/src/shim/cast/classes/SessionRequest.ts new file mode 100755 index 0000000..68f7564 --- /dev/null +++ b/ext/src/shim/cast/classes/SessionRequest.ts @@ -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) {} +}; diff --git a/ext/src/shim/cast/classes/Timeout.js b/ext/src/shim/cast/classes/Timeout.ts similarity index 77% rename from ext/src/shim/cast/classes/Timeout.js rename to ext/src/shim/cast/classes/Timeout.ts index c250855..81e6014 100755 --- a/ext/src/shim/cast/classes/Timeout.js +++ b/ext/src/shim/cast/classes/Timeout.ts @@ -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); + } +}; diff --git a/ext/src/shim/cast/classes/Volume.js b/ext/src/shim/cast/classes/Volume.ts similarity index 56% rename from ext/src/shim/cast/classes/Volume.js rename to ext/src/shim/cast/classes/Volume.ts index c56b934..78e98e2 100755 --- a/ext/src/shim/cast/classes/Volume.js +++ b/ext/src/shim/cast/classes/Volume.ts @@ -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) { + } +}; diff --git a/ext/src/shim/cast/classes/index.js b/ext/src/shim/cast/classes/index.js deleted file mode 100755 index 563ed88..0000000 --- a/ext/src/shim/cast/classes/index.js +++ /dev/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 -}; diff --git a/ext/src/shim/cast/enums/index.js b/ext/src/shim/cast/enums/index.ts similarity index 95% rename from ext/src/shim/cast/enums/index.js rename to ext/src/shim/cast/enums/index.ts index f5b6b5a..7a3c24b 100755 --- a/ext/src/shim/cast/enums/index.js +++ b/ext/src/shim/cast/enums/index.ts @@ -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" +}; diff --git a/ext/src/shim/cast/index.js b/ext/src/shim/cast/index.js deleted file mode 100755 index 1b94fa6..0000000 --- a/ext/src/shim/cast/index.js +++ /dev/null @@ -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; diff --git a/ext/src/shim/cast/index.ts b/ext/src/shim/cast/index.ts new file mode 100755 index 0000000..18c482b --- /dev/null +++ b/ext/src/shim/cast/index.ts @@ -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(); + +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; + } + } +}); diff --git a/ext/src/shim/content.js b/ext/src/shim/content.js deleted file mode 100644 index 0a7fb94..0000000 --- a/ext/src/shim/content.js +++ /dev/null @@ -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); - } - } -}); diff --git a/ext/src/shim/content.ts b/ext/src/shim/content.ts new file mode 100644 index 0000000..4fb2b0c --- /dev/null +++ b/ext/src/shim/content.ts @@ -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); + } +}); diff --git a/ext/src/shim/contentSetup.js b/ext/src/shim/contentSetup.js deleted file mode 100644 index 480a1b5..0000000 --- a/ext/src/shim/contentSetup.js +++ /dev/null @@ -1,3 +0,0 @@ -"use strict"; - -window.wrappedJSObject.chrome = cloneInto({}, window); diff --git a/ext/src/shim/contentSetup.ts b/ext/src/shim/contentSetup.ts new file mode 100644 index 0000000..f59905c --- /dev/null +++ b/ext/src/shim/contentSetup.ts @@ -0,0 +1,3 @@ +"use strict"; + +(window.wrappedJSObject as any).chrome = cloneInto({}, window); diff --git a/ext/src/shim/index.js b/ext/src/shim/index.ts similarity index 66% rename from ext/src/shim/index.js rename to ext/src/shim/index.ts index c7f275d..edf94ca 100755 --- a/ext/src/shim/index.js +++ b/ext/src/shim/index.ts @@ -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; - }; + } } }); diff --git a/ext/src/shim/media/classes/EditTracksInfoRequest.js b/ext/src/shim/media/classes/EditTracksInfoRequest.js deleted file mode 100644 index 8f3daeb..0000000 --- a/ext/src/shim/media/classes/EditTracksInfoRequest.js +++ /dev/null @@ -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; - } -} diff --git a/ext/src/shim/media/classes/EditTracksInfoRequest.ts b/ext/src/shim/media/classes/EditTracksInfoRequest.ts new file mode 100644 index 0000000..46b6578 --- /dev/null +++ b/ext/src/shim/media/classes/EditTracksInfoRequest.ts @@ -0,0 +1,10 @@ +"use strict"; + +export default class EditTracksInfoRequest { + public requestId = 0; + + constructor ( + public activeTrackIds: number[] = null + , public textTrackStyle: string = null) { + } +} diff --git a/ext/src/shim/media/classes/GenericMediaMetadata.js b/ext/src/shim/media/classes/GenericMediaMetadata.js deleted file mode 100644 index 83ff3b8..0000000 --- a/ext/src/shim/media/classes/GenericMediaMetadata.js +++ /dev/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; - } -} diff --git a/ext/src/shim/media/classes/GenericMediaMetadata.ts b/ext/src/shim/media/classes/GenericMediaMetadata.ts new file mode 100644 index 0000000..ffe5837 --- /dev/null +++ b/ext/src/shim/media/classes/GenericMediaMetadata.ts @@ -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; +} diff --git a/ext/src/shim/media/classes/GetStatusRequest.js b/ext/src/shim/media/classes/GetStatusRequest.js deleted file mode 100644 index afb7a47..0000000 --- a/ext/src/shim/media/classes/GetStatusRequest.js +++ /dev/null @@ -1,7 +0,0 @@ -"use strict"; - -export default class GetStatusRequest { - constructor () { - this.customData = null; - } -} diff --git a/ext/src/shim/media/classes/GetStatusRequest.ts b/ext/src/shim/media/classes/GetStatusRequest.ts new file mode 100644 index 0000000..af95d34 --- /dev/null +++ b/ext/src/shim/media/classes/GetStatusRequest.ts @@ -0,0 +1,5 @@ +"use strict"; + +export default class GetStatusRequest { + public customData: any = null; +} diff --git a/ext/src/shim/media/classes/LoadRequest.js b/ext/src/shim/media/classes/LoadRequest.js deleted file mode 100644 index 5b3cbda..0000000 --- a/ext/src/shim/media/classes/LoadRequest.js +++ /dev/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"; - } -} diff --git a/ext/src/shim/media/classes/LoadRequest.ts b/ext/src/shim/media/classes/LoadRequest.ts new file mode 100644 index 0000000..b729eac --- /dev/null +++ b/ext/src/shim/media/classes/LoadRequest.ts @@ -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; + } +} diff --git a/ext/src/shim/media/classes/Media.js b/ext/src/shim/media/classes/Media.js deleted file mode 100644 index 6b1ee9c..0000000 --- a/ext/src/shim/media/classes/Media.js +++ /dev/null @@ -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"); - } -} diff --git a/ext/src/shim/media/classes/Media.ts b/ext/src/shim/media/classes/Media.ts new file mode 100644 index 0000000..86c0da4 --- /dev/null +++ b/ext/src/shim/media/classes/Media.ts @@ -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(); + 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 + }); + } +} diff --git a/ext/src/shim/media/classes/MediaInfo.js b/ext/src/shim/media/classes/MediaInfo.js deleted file mode 100644 index 90e40ca..0000000 --- a/ext/src/shim/media/classes/MediaInfo.js +++ /dev/null @@ -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; - } -} diff --git a/ext/src/shim/media/classes/MediaInfo.ts b/ext/src/shim/media/classes/MediaInfo.ts new file mode 100644 index 0000000..308f086 --- /dev/null +++ b/ext/src/shim/media/classes/MediaInfo.ts @@ -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) {} +} diff --git a/ext/src/shim/media/classes/MovieMediaMetadata.js b/ext/src/shim/media/classes/MovieMediaMetadata.js deleted file mode 100644 index 5df3b67..0000000 --- a/ext/src/shim/media/classes/MovieMediaMetadata.js +++ /dev/null @@ -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; - } -} diff --git a/ext/src/shim/media/classes/MovieMediaMetadata.ts b/ext/src/shim/media/classes/MovieMediaMetadata.ts new file mode 100644 index 0000000..03d5e5a --- /dev/null +++ b/ext/src/shim/media/classes/MovieMediaMetadata.ts @@ -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; +} diff --git a/ext/src/shim/media/classes/MusicTrackMediaMetadata.js b/ext/src/shim/media/classes/MusicTrackMediaMetadata.js deleted file mode 100644 index 09b5703..0000000 --- a/ext/src/shim/media/classes/MusicTrackMediaMetadata.js +++ /dev/null @@ -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; - } -} diff --git a/ext/src/shim/media/classes/MusicTrackMediaMetadata.ts b/ext/src/shim/media/classes/MusicTrackMediaMetadata.ts new file mode 100644 index 0000000..b23bf15 --- /dev/null +++ b/ext/src/shim/media/classes/MusicTrackMediaMetadata.ts @@ -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; +} diff --git a/ext/src/shim/media/classes/PauseRequest.js b/ext/src/shim/media/classes/PauseRequest.js deleted file mode 100644 index a7340da..0000000 --- a/ext/src/shim/media/classes/PauseRequest.js +++ /dev/null @@ -1,7 +0,0 @@ -"use strict"; - -export default class PauseRequest { - constructor () { - this.customData = null; - } -} diff --git a/ext/src/shim/media/classes/PauseRequest.ts b/ext/src/shim/media/classes/PauseRequest.ts new file mode 100644 index 0000000..bcc1179 --- /dev/null +++ b/ext/src/shim/media/classes/PauseRequest.ts @@ -0,0 +1,5 @@ +"use strict"; + +export default class PauseRequest { + public customData: any = null; +} diff --git a/ext/src/shim/media/classes/PhotoMediaMetadata.js b/ext/src/shim/media/classes/PhotoMediaMetadata.js deleted file mode 100644 index 577e313..0000000 --- a/ext/src/shim/media/classes/PhotoMediaMetadata.js +++ /dev/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; - } -} diff --git a/ext/src/shim/media/classes/PhotoMediaMetadata.ts b/ext/src/shim/media/classes/PhotoMediaMetadata.ts new file mode 100644 index 0000000..da72c63 --- /dev/null +++ b/ext/src/shim/media/classes/PhotoMediaMetadata.ts @@ -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; +} diff --git a/ext/src/shim/media/classes/PlayRequest.js b/ext/src/shim/media/classes/PlayRequest.js deleted file mode 100644 index a92328c..0000000 --- a/ext/src/shim/media/classes/PlayRequest.js +++ /dev/null @@ -1,7 +0,0 @@ -"use strict"; - -export default class PlayRequest { - constructor () { - this.customData = null; - } -} diff --git a/ext/src/shim/media/classes/PlayRequest.ts b/ext/src/shim/media/classes/PlayRequest.ts new file mode 100644 index 0000000..9557e51 --- /dev/null +++ b/ext/src/shim/media/classes/PlayRequest.ts @@ -0,0 +1,5 @@ +"use strict"; + +export default class PlayRequest { + public customData: any = null; +} diff --git a/ext/src/shim/media/classes/QueueInsertItemsRequest.js b/ext/src/shim/media/classes/QueueInsertItemsRequest.js deleted file mode 100644 index 7d73513..0000000 --- a/ext/src/shim/media/classes/QueueInsertItemsRequest.js +++ /dev/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"; - } -} diff --git a/ext/src/shim/media/classes/QueueInsertItemsRequest.ts b/ext/src/shim/media/classes/QueueInsertItemsRequest.ts new file mode 100644 index 0000000..f2bb8ba --- /dev/null +++ b/ext/src/shim/media/classes/QueueInsertItemsRequest.ts @@ -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[]) {} +} diff --git a/ext/src/shim/media/classes/QueueItem.js b/ext/src/shim/media/classes/QueueItem.js deleted file mode 100644 index e7ed34b..0000000 --- a/ext/src/shim/media/classes/QueueItem.js +++ /dev/null @@ -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; - } -} diff --git a/ext/src/shim/media/classes/QueueItem.ts b/ext/src/shim/media/classes/QueueItem.ts new file mode 100644 index 0000000..64d12e1 --- /dev/null +++ b/ext/src/shim/media/classes/QueueItem.ts @@ -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; + } +} diff --git a/ext/src/shim/media/classes/QueueLoadRequest.js b/ext/src/shim/media/classes/QueueLoadRequest.js deleted file mode 100644 index dc36b5e..0000000 --- a/ext/src/shim/media/classes/QueueLoadRequest.js +++ /dev/null @@ -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"; - } -} diff --git a/ext/src/shim/media/classes/QueueLoadRequest.ts b/ext/src/shim/media/classes/QueueLoadRequest.ts new file mode 100644 index 0000000..80fc4a8 --- /dev/null +++ b/ext/src/shim/media/classes/QueueLoadRequest.ts @@ -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[]) {} +} diff --git a/ext/src/shim/media/classes/QueueRemoveItemsRequest.js b/ext/src/shim/media/classes/QueueRemoveItemsRequest.js deleted file mode 100644 index 4f3c586..0000000 --- a/ext/src/shim/media/classes/QueueRemoveItemsRequest.js +++ /dev/null @@ -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"; - } -} diff --git a/ext/src/shim/media/classes/QueueRemoveItemsRequest.ts b/ext/src/shim/media/classes/QueueRemoveItemsRequest.ts new file mode 100644 index 0000000..9e95136 --- /dev/null +++ b/ext/src/shim/media/classes/QueueRemoveItemsRequest.ts @@ -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[]) {} +} diff --git a/ext/src/shim/media/classes/QueueReorderItemsRequest.js b/ext/src/shim/media/classes/QueueReorderItemsRequest.js deleted file mode 100644 index 37229da..0000000 --- a/ext/src/shim/media/classes/QueueReorderItemsRequest.js +++ /dev/null @@ -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"; - } -} diff --git a/ext/src/shim/media/classes/QueueReorderItemsRequest.ts b/ext/src/shim/media/classes/QueueReorderItemsRequest.ts new file mode 100644 index 0000000..26ffb4e --- /dev/null +++ b/ext/src/shim/media/classes/QueueReorderItemsRequest.ts @@ -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[]) {} +} diff --git a/ext/src/shim/media/classes/QueueSetPropertiesRequest.js b/ext/src/shim/media/classes/QueueSetPropertiesRequest.js deleted file mode 100644 index c1e2006..0000000 --- a/ext/src/shim/media/classes/QueueSetPropertiesRequest.js +++ /dev/null @@ -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"; - } -} diff --git a/ext/src/shim/media/classes/QueueSetPropertiesRequest.ts b/ext/src/shim/media/classes/QueueSetPropertiesRequest.ts new file mode 100644 index 0000000..799f6c4 --- /dev/null +++ b/ext/src/shim/media/classes/QueueSetPropertiesRequest.ts @@ -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"; +} diff --git a/ext/src/shim/media/classes/QueueUpdateItemsRequest.js b/ext/src/shim/media/classes/QueueUpdateItemsRequest.js deleted file mode 100644 index b9cfb3d..0000000 --- a/ext/src/shim/media/classes/QueueUpdateItemsRequest.js +++ /dev/null @@ -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"; - } -} diff --git a/ext/src/shim/media/classes/QueueUpdateItemsRequest.ts b/ext/src/shim/media/classes/QueueUpdateItemsRequest.ts new file mode 100644 index 0000000..31c71c2 --- /dev/null +++ b/ext/src/shim/media/classes/QueueUpdateItemsRequest.ts @@ -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[]) {} +} diff --git a/ext/src/shim/media/classes/SeekRequest.js b/ext/src/shim/media/classes/SeekRequest.js deleted file mode 100644 index 29fd580..0000000 --- a/ext/src/shim/media/classes/SeekRequest.js +++ /dev/null @@ -1,9 +0,0 @@ -"use strict"; - -export default class SeekRequest { - constructor () { - this.currentTime = null; - this.customData = null; - this.resumeState = null; - } -} diff --git a/ext/src/shim/media/classes/SeekRequest.ts b/ext/src/shim/media/classes/SeekRequest.ts new file mode 100644 index 0000000..e87f43e --- /dev/null +++ b/ext/src/shim/media/classes/SeekRequest.ts @@ -0,0 +1,7 @@ +"use strict"; + +export default class SeekRequest { + public currentTime: number = null; + public customData: any = null; + public resumeState: string = null; +} diff --git a/ext/src/shim/media/classes/StopRequest.js b/ext/src/shim/media/classes/StopRequest.js deleted file mode 100644 index 35be356..0000000 --- a/ext/src/shim/media/classes/StopRequest.js +++ /dev/null @@ -1,7 +0,0 @@ -"use strict"; - -export default class StopRequest { - constructor () { - this.customData = null; - } -} diff --git a/ext/src/shim/media/classes/StopRequest.ts b/ext/src/shim/media/classes/StopRequest.ts new file mode 100644 index 0000000..90acfa5 --- /dev/null +++ b/ext/src/shim/media/classes/StopRequest.ts @@ -0,0 +1,5 @@ +"use strict"; + +export default class StopRequest { + public customData: any = null; +} diff --git a/ext/src/shim/media/classes/TextTrackStyle.js b/ext/src/shim/media/classes/TextTrackStyle.js deleted file mode 100644 index 01aa3f4..0000000 --- a/ext/src/shim/media/classes/TextTrackStyle.js +++ /dev/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; - } -} diff --git a/ext/src/shim/media/classes/TextTrackStyle.ts b/ext/src/shim/media/classes/TextTrackStyle.ts new file mode 100644 index 0000000..11b132a --- /dev/null +++ b/ext/src/shim/media/classes/TextTrackStyle.ts @@ -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; +} diff --git a/ext/src/shim/media/classes/Track.js b/ext/src/shim/media/classes/Track.js deleted file mode 100644 index dcd32ce..0000000 --- a/ext/src/shim/media/classes/Track.js +++ /dev/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; - } -} diff --git a/ext/src/shim/media/classes/Track.ts b/ext/src/shim/media/classes/Track.ts new file mode 100644 index 0000000..f436aea --- /dev/null +++ b/ext/src/shim/media/classes/Track.ts @@ -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) {} +} diff --git a/ext/src/shim/media/classes/TvShowMediaMetadata.js b/ext/src/shim/media/classes/TvShowMediaMetadata.js deleted file mode 100644 index de02768..0000000 --- a/ext/src/shim/media/classes/TvShowMediaMetadata.js +++ /dev/null @@ -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; - } -} diff --git a/ext/src/shim/media/classes/TvShowMediaMetadata.ts b/ext/src/shim/media/classes/TvShowMediaMetadata.ts new file mode 100644 index 0000000..37536e1 --- /dev/null +++ b/ext/src/shim/media/classes/TvShowMediaMetadata.ts @@ -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; +} diff --git a/ext/src/shim/media/classes/VolumeRequest.js b/ext/src/shim/media/classes/VolumeRequest.js deleted file mode 100644 index c6173d3..0000000 --- a/ext/src/shim/media/classes/VolumeRequest.js +++ /dev/null @@ -1,8 +0,0 @@ -"use strict"; - -export default class VolumeRequest { - constructor (volume) { - this.customData = null; - this.volume = volume; - } -} diff --git a/ext/src/shim/media/classes/VolumeRequest.ts b/ext/src/shim/media/classes/VolumeRequest.ts new file mode 100644 index 0000000..55d959e --- /dev/null +++ b/ext/src/shim/media/classes/VolumeRequest.ts @@ -0,0 +1,11 @@ +"use strict"; + +import Volume from "../../cast/classes/Volume"; + + +export default class VolumeRequest { + public customData: any = null; + + constructor ( + public volume: Volume) {} +} diff --git a/ext/src/shim/media/enums/index.js b/ext/src/shim/media/enums/index.ts similarity index 95% rename from ext/src/shim/media/enums/index.js rename to ext/src/shim/media/enums/index.ts index 2408ed4..dd07412 100755 --- a/ext/src/shim/media/enums/index.js +++ b/ext/src/shim/media/enums/index.ts @@ -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" +}; diff --git a/ext/src/shim/media/index.js b/ext/src/shim/media/index.js deleted file mode 100755 index c62663f..0000000 --- a/ext/src/shim/media/index.js +++ /dev/null @@ -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" -}; diff --git a/ext/src/shim/media/index.ts b/ext/src/shim/media/index.ts new file mode 100755 index 0000000..52cf558 --- /dev/null +++ b/ext/src/shim/media/index.ts @@ -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" +}; diff --git a/ext/src/shim/messageBridge.js b/ext/src/shim/messageBridge.ts similarity index 63% rename from ext/src/shim/messageBridge.js rename to ext/src/shim/messageBridge.ts index eb43319..fc7e957 100644 --- a/ext/src/shim/messageBridge.js +++ b/ext/src/shim/messageBridge.ts @@ -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) }); diff --git a/ext/src/shim/state.js b/ext/src/shim/state.js deleted file mode 100755 index 2b9476f..0000000 --- a/ext/src/shim/state.js +++ /dev/null @@ -1,11 +0,0 @@ -"use strict"; - -// Global API state -const state = { - apiConfig: null - , receiverList: [] - , sessionList: [] - , sessionRequestInProgress: false -}; - -export default state; diff --git a/ext/src/shim/state.ts b/ext/src/shim/state.ts new file mode 100755 index 0000000..7ebab67 --- /dev/null +++ b/ext/src/shim/state.ts @@ -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; diff --git a/ext/src/shim/timeout.js b/ext/src/shim/timeout.ts similarity index 96% rename from ext/src/shim/timeout.js rename to ext/src/shim/timeout.ts index 0b29f02..b66c437 100755 --- a/ext/src/shim/timeout.js +++ b/ext/src/shim/timeout.ts @@ -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; diff --git a/ext/src/shim/types.ts b/ext/src/shim/types.ts new file mode 100644 index 0000000..3e04d56 --- /dev/null +++ b/ext/src/shim/types.ts @@ -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; diff --git a/ext/src/types.ts b/ext/src/types.ts index c591b0b..a8e72a4 100644 --- a/ext/src/types.ts +++ b/ext/src/types.ts @@ -2,7 +2,8 @@ export interface Message { subject: string; - data: any; + data?: any; + _id?: string; } export interface Receiver { diff --git a/ext/webpack.config.js b/ext/webpack.config.js index 977e089..5e95764 100755 --- a/ext/webpack.config.js +++ b/ext/webpack.config.js @@ -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")) { diff --git a/package-lock.json b/package-lock.json index 8a38abf..9dd6c85 100644 --- a/package-lock.json +++ b/package-lock.json @@ -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", diff --git a/package.json b/package.json index 9d2dad5..07e3ab3 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/test/driver.js b/test/driver.js index dfba224..593c321 100644 --- a/test/driver.js +++ b/test/driver.js @@ -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.");