Convert mediaCast sender to typescript

This commit is contained in:
hensm
2019-06-14 12:49:10 +01:00
parent 2996e50f5e
commit 0427e08b6a
5 changed files with 127 additions and 90 deletions

View File

@@ -429,17 +429,17 @@ browser.menus.onClicked.addListener(async (info, tab) => {
const { frameId } = info; const { frameId } = info;
const mirroringAppId = await options.get("mirroringAppId"); const mirroringAppId = await options.get("mirroringAppId");
switch (info.menuItemId) {
case mirrorCastMenuId: {
mirrorCastTabId = tab.id;
mirrorCastFrameId = frameId;
// Load cast setup script // Load cast setup script
await browser.tabs.executeScript(tab.id, { await browser.tabs.executeScript(tab.id, {
file: "shim/content.js" file: "shim/content.js"
, frameId , frameId
}); });
switch (info.menuItemId) {
case mirrorCastMenuId: {
mirrorCastTabId = tab.id;
mirrorCastFrameId = frameId;
await browser.tabs.executeScript(tab.id, { await browser.tabs.executeScript(tab.id, {
code: ` code: `
var selectedMedia = ${info.pageUrl var selectedMedia = ${info.pageUrl
@@ -456,6 +456,12 @@ browser.menus.onClicked.addListener(async (info, tab) => {
, frameId , frameId
}); });
// Load cast API
await browser.tabs.executeScript(tab.id, {
file: "shim/bundle.js"
, frameId
});
break; break;
} }
@@ -465,8 +471,10 @@ browser.menus.onClicked.addListener(async (info, tab) => {
// Pass media URL to media sender app // Pass media URL to media sender app
await browser.tabs.executeScript(tab.id, { await browser.tabs.executeScript(tab.id, {
code: `var srcUrl = "${info.srcUrl}"; code: `
var targetElementId = ${info.targetElementId};` window.srcUrl = "${info.srcUrl}";
window.targetElementId = ${info.targetElementId};
`
, frameId , frameId
}); });
@@ -480,12 +488,6 @@ browser.menus.onClicked.addListener(async (info, tab) => {
} }
} }
// Load cast API
await browser.tabs.executeScript(tab.id, {
file: "shim/bundle.js"
, frameId
});
return; return;
} }

View File

@@ -1,20 +1,28 @@
"use strict"; "use strict";
let options; import { Options } from "../defaultOptions";
import cast, { init } from "../shim/export";
let chrome;
let logMessage;
let session; // Variables passed from background
let currentMedia; const { srcUrl
, targetElementId }
: { srcUrl: string
, targetElementId: number } = (window as any);
let options: Options;
let session: cast.Session;
let currentMedia: cast.media.Media;
let ignoreMediaEvents = false; let ignoreMediaEvents = false;
const isLocalFile = srcUrl.startsWith("file:"); const isLocalFile = srcUrl.startsWith("file:");
const mediaElement = browser.menus.getTargetElement(targetElementId); const mediaElement = browser.menus.getTargetElement(
targetElementId) as HTMLMediaElement;
window.addEventListener("beforeunload", () => { window.addEventListener("beforeunload", () => {
browser.runtime.sendMessage({ browser.runtime.sendMessage({
@@ -22,7 +30,7 @@ window.addEventListener("beforeunload", () => {
}); });
if (options.mediaStopOnUnload) { if (options.mediaStopOnUnload) {
session.stop(); session.stop(null, null);
/*currentMedia.stop(null /*currentMedia.stop(null
, onMediaStopSuccess , onMediaStopSuccess
, onMediaStopError);*/ , onMediaStopError);*/
@@ -47,8 +55,8 @@ function getLocalAddress () {
} }
async function onRequestSessionSuccess (session_) { async function onRequestSessionSuccess (session_: cast.Session) {
logMessage("onRequestSessionSuccess"); cast.logMessage("onRequestSessionSuccess");
session = session_; session = session_;
@@ -77,16 +85,16 @@ async function onRequestSessionSuccess (session_) {
mediaUrl = new URL(`http://${await getLocalAddress()}:${port}/`); mediaUrl = new URL(`http://${await getLocalAddress()}:${port}/`);
} }
const mediaInfo = new chrome.cast.media.MediaInfo(mediaUrl.href); const mediaInfo = new cast.media.MediaInfo(mediaUrl.href, null);
// Media metadata (title/poster) // Media metadata (title/poster)
mediaInfo.metadata = new chrome.cast.media.GenericMediaMetadata(); mediaInfo.metadata = new cast.media.GenericMediaMetadata();
mediaInfo.metadata.metadataType = chrome.cast.media.MetadataType.GENERIC; mediaInfo.metadata.metadataType = cast.media.MetadataType.GENERIC;
mediaInfo.metadata.title = mediaUrl.pathname; mediaInfo.metadata.title = mediaUrl.pathname;
if (mediaElement.poster) { if (mediaElement instanceof HTMLVideoElement && mediaElement.poster) {
mediaInfo.metadata.images = [ mediaInfo.metadata.images = [
new chrome.cast.Image(mediaElement.poster) new cast.Image(mediaElement.poster)
]; ];
} }
@@ -97,13 +105,13 @@ async function onRequestSessionSuccess (session_) {
const trackElements = mediaElement.querySelectorAll("track"); const trackElements = mediaElement.querySelectorAll("track");
let index = 0; let index = 0;
for (const textTrack of mediaElement.textTracks) { for (const textTrack of Array.from(mediaElement.textTracks)) {
const trackElement = trackElements[index]; const trackElement = trackElements[index];
// Create Track object // Create Track object
const track = new chrome.cast.media.Track( const track = new cast.media.Track(
index // trackId index // trackId
, chrome.cast.media.TrackType.TEXT); // trackType , cast.media.TrackType.TEXT); // trackType
// Copy TextTrack properties to Track // Copy TextTrack properties to Track
track.name = textTrack.label; track.name = textTrack.label;
@@ -111,7 +119,7 @@ async function onRequestSessionSuccess (session_) {
track.trackContentId = trackElement.src; track.trackContentId = trackElement.src;
track.trackContentType = "text/vtt"; track.trackContentType = "text/vtt";
const { TextTrackType } = chrome.cast.media; const { TextTrackType } = cast.media;
switch (textTrack.kind) { switch (textTrack.kind) {
case "subtitles": case "subtitles":
@@ -147,7 +155,7 @@ async function onRequestSessionSuccess (session_) {
} }
} }
const loadRequest = new chrome.cast.media.LoadRequest(mediaInfo); const loadRequest = new cast.media.LoadRequest(mediaInfo);
loadRequest.autoplay = false; loadRequest.autoplay = false;
loadRequest.activeTrackIds = activeTrackIds; loadRequest.activeTrackIds = activeTrackIds;
@@ -156,31 +164,31 @@ async function onRequestSessionSuccess (session_) {
, onLoadMediaError); , onLoadMediaError);
} }
function onRequestSessionError () { function onRequestSessionError () {
logMessage("onRequestSessionError"); cast.logMessage("onRequestSessionError");
} }
function sessionListener (session) { function sessionListener (session: cast.Session) {
logMessage("sessionListener"); cast.logMessage("sessionListener");
} }
function receiverListener (availability) { function receiverListener (availability: string) {
logMessage("receiverListener"); cast.logMessage("receiverListener");
if (availability === chrome.cast.ReceiverAvailability.AVAILABLE) { if (availability === cast.ReceiverAvailability.AVAILABLE) {
chrome.cast.requestSession( cast.requestSession(
onRequestSessionSuccess onRequestSessionSuccess
, onRequestSessionError); , onRequestSessionError);
} }
} }
function onInitializeSuccess () { function onInitializeSuccess () {
logMessage("onInitializeSuccess"); cast.logMessage("onInitializeSuccess");
} }
function onInitializeError () { function onInitializeError () {
logMessage("onInitializeError"); cast.logMessage("onInitializeError");
} }
function onLoadMediaSuccess (media) { function onLoadMediaSuccess (media: cast.media.Media) {
logMessage("onLoadMediaSuccess"); cast.logMessage("onLoadMediaSuccess");
currentMedia = media; currentMedia = media;
@@ -219,7 +227,7 @@ function onLoadMediaSuccess (media) {
return; return;
} }
const seekRequest = new chrome.cast.media.SeekRequest(); const seekRequest = new cast.media.SeekRequest();
seekRequest.currentTime = mediaElement.currentTime; seekRequest.currentTime = mediaElement.currentTime;
currentMedia.seek(seekRequest currentMedia.seek(seekRequest
@@ -228,21 +236,21 @@ function onLoadMediaSuccess (media) {
}); });
mediaElement.addEventListener("ratechange", () => { mediaElement.addEventListener("ratechange", () => {
currentMedia._sendMediaMessage({ (currentMedia as any)._sendMediaMessage({
type: "SET_PLAYBACK_RATE" type: "SET_PLAYBACK_RATE"
, playbackRate: mediaElement.playbackRate , playbackRate: mediaElement.playbackRate
}); });
}); });
mediaElement.addEventListener("volumechange", () => { mediaElement.addEventListener("volumechange", () => {
const newVolume = new chrome.cast.Volume( const newVolume = new cast.Volume(
currentMedia.volume currentMedia.volume.level
, currentMedia.muted); , currentMedia.volume.muted);
const volumeRequest = const volumeRequest =
new chrome.cast.media.VolumeRequest(newVolume); new cast.media.VolumeRequest(newVolume);
logMessage("Volume change"); cast.logMessage("Volume change");
currentMedia.setVolume(volumeRequest); currentMedia.setVolume(volumeRequest);
}); });
@@ -254,17 +262,17 @@ function onLoadMediaSuccess (media) {
// PlayerState // PlayerState
const localPlayerState = mediaElement.paused const localPlayerState = mediaElement.paused
? chrome.cast.media.PlayerState.PAUSED ? cast.media.PlayerState.PAUSED
: chrome.cast.media.PlayerState.PLAYING; : cast.media.PlayerState.PLAYING;
if (localPlayerState !== currentMedia.playerState) { if (localPlayerState !== currentMedia.playerState) {
ignoreMediaEvents = true; ignoreMediaEvents = true;
switch (currentMedia.playerState) { switch (currentMedia.playerState) {
case chrome.cast.media.PlayerState.PLAYING: case cast.media.PlayerState.PLAYING:
mediaElement.play(); mediaElement.play();
break; break;
case chrome.cast.media.PlayerState.PAUSED: case cast.media.PlayerState.PAUSED:
mediaElement.pause(); mediaElement.pause();
break; break;
} }
@@ -272,17 +280,17 @@ function onLoadMediaSuccess (media) {
// RepeatMode // RepeatMode
const localRepeatMode = mediaElement.loop const localRepeatMode = mediaElement.loop
? chrome.cast.media.RepeatMode.SINGLE ? cast.media.RepeatMode.SINGLE
: chrome.cast.media.RepeatMode.OFF; : cast.media.RepeatMode.OFF;
if (localRepeatMode !== currentMedia.repeatMode) { if (localRepeatMode !== currentMedia.repeatMode) {
ignoreMediaEvents = true; ignoreMediaEvents = true;
switch (currentMedia.repeatMode) { switch (currentMedia.repeatMode) {
case chrome.cast.media.RepeatMode.SINGLE: case cast.media.RepeatMode.SINGLE:
mediaElement.loop = true; mediaElement.loop = true;
break; break;
case chrome.cast.media.RepeatMode.OFF: case cast.media.RepeatMode.OFF:
mediaElement.loop = false; mediaElement.loop = false;
break; break;
} }
@@ -298,70 +306,64 @@ function onLoadMediaSuccess (media) {
} }
} }
function onLoadMediaError () { function onLoadMediaError () {
logMessage("onLoadMediaError"); cast.logMessage("onLoadMediaError");
} }
/* play */ /* play */
function onMediaPlaySuccess () { function onMediaPlaySuccess () {
logMessage("onMediaPlaySuccess"); cast.logMessage("onMediaPlaySuccess");
} }
function onMediaPlayError (err) { function onMediaPlayError (err: cast.Error) {
logMessage("onMediaPlayError"); cast.logMessage("onMediaPlayError");
} }
/* pause */ /* pause */
function onMediaPauseSuccess () { function onMediaPauseSuccess () {
logMessage("onMediaPauseSuccess"); cast.logMessage("onMediaPauseSuccess");
} }
function onMediaPauseError (err) { function onMediaPauseError (err: cast.Error) {
logMessage("onMediaPauseError"); cast.logMessage("onMediaPauseError");
} }
/* stop */ /* stop */
function onMediaStopSuccess () { function onMediaStopSuccess () {
logMessage("onMediaStopSuccess"); cast.logMessage("onMediaStopSuccess");
} }
function onMediaStopError (err) { function onMediaStopError (err: cast.Error) {
logMessage("onMediaStopError"); cast.logMessage("onMediaStopError");
} }
/* seek */ /* seek */
function onMediaSeekSuccess () { function onMediaSeekSuccess () {
logMessage("onMediaSeekSuccess"); cast.logMessage("onMediaSeekSuccess");
} }
function onMediaSeekError (err) { function onMediaSeekError (err: cast.Error) {
logMessage("onMediaSeekError"); cast.logMessage("onMediaSeekError");
} }
window.__onGCastApiAvailable = async function (loaded, errorInfo) { init().then(async bridgeInfo => {
if (!loaded) { if (!bridgeInfo.isVersionCompatible) {
console.error("__onGCastApiAvailable error"); console.error("__onGCastApiAvailable error");
return; return;
} }
chrome = window.chrome;
logMessage = chrome.cast.logMessage;
logMessage("__onGCastApiAvailable success");
options = (await browser.storage.sync.get("options")).options; options = (await browser.storage.sync.get("options")).options;
if (isLocalFile && !options.localMediaEnabled) { if (isLocalFile && !options.localMediaEnabled) {
logMessage("Local media casting not enabled"); cast.logMessage("Local media casting not enabled");
return; return;
} }
const sessionRequest = new chrome.cast.SessionRequest( const sessionRequest = new cast.SessionRequest(
chrome.cast.media.DEFAULT_MEDIA_RECEIVER_APP_ID); cast.media.DEFAULT_MEDIA_RECEIVER_APP_ID);
const apiConfig = new chrome.cast.ApiConfig(sessionRequest const apiConfig = new cast.ApiConfig(sessionRequest
, sessionListener , sessionListener
, receiverListener); , receiverListener);
chrome.cast.initialize(apiConfig cast.initialize(apiConfig
, onInitializeSuccess , onInitializeSuccess
, onInitializeError); , onInitializeError);
}; });

34
ext/src/shim/export.ts Normal file
View File

@@ -0,0 +1,34 @@
"use strict";
import * as cast from "./cast";
import { BridgeInfo } from "../lib/getBridgeInfo";
import { Message } from "../types";
import { onMessage } from "./messageBridge";
/**
* To support exporting an API from a module, we need to
* retain the event-based message passing despite not
* actually crossing any context boundaries. The shim listens
* for and emits these messages, and changing that behavior
* is too messy.
*/
export function init (): Promise<BridgeInfo> {
return new Promise(async (resolve, reject) => {
// Trigger message port setup side-effects
import("./content");
onMessage(message => {
switch (message.subject) {
case "shim:/initialized": {
const bridgeInfo: BridgeInfo = message.data;
resolve(bridgeInfo);
}
}
})
});
}
export default cast;

View File

@@ -2,9 +2,8 @@
import * as cast from "./cast"; import * as cast from "./cast";
import { onMessage } from "./messageBridge";
import { loadScript } from "../lib/utils"; import { loadScript } from "../lib/utils";
import { onMessage } from "./messageBridge";
const _window = (window as any); const _window = (window as any);

View File

@@ -20,7 +20,7 @@ module.exports = (env) => ({
, "ui/updater/bundle": `${env.includePath}/ui/updater/index.tsx` , "ui/updater/bundle": `${env.includePath}/ui/updater/index.tsx`
// Sender apps // Sender apps
, "senders/mediaCast": `${env.includePath}/senders/mediaCast.js` , "senders/mediaCast": `${env.includePath}/senders/mediaCast.ts`
, "senders/mirroringCast": `${env.includePath}/senders/mirroringCast.js` , "senders/mirroringCast": `${env.includePath}/senders/mirroringCast.js`
// Shim entries // Shim entries