mirror of
https://github.com/hensm/fx_cast.git
synced 2026-06-12 10:39:57 +00:00
Refactor menus module
This commit is contained in:
@@ -16,8 +16,8 @@ const _ = browser.i18n.getMessage;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* On install, set the default options before initializing the
|
* On install, set the default options before initializing the
|
||||||
* extension. On update, handle any unset values and set to
|
* extension. On update, handle any unset values and set to the new
|
||||||
* the new defaults.
|
* defaults.
|
||||||
*/
|
*/
|
||||||
browser.runtime.onInstalled.addListener(async details => {
|
browser.runtime.onInstalled.addListener(async details => {
|
||||||
switch (details.reason) {
|
switch (details.reason) {
|
||||||
@@ -39,9 +39,9 @@ browser.runtime.onInstalled.addListener(async details => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks whether the bridge can be reached and is compatible
|
* Checks whether the bridge can be reached and is compatible with the
|
||||||
* with the current version of the extension. If not, triggers
|
* current version of the extension. If not, triggers a notification
|
||||||
* a notification with the appropriate info.
|
* with the appropriate info.
|
||||||
*/
|
*/
|
||||||
async function notifyBridgeCompat() {
|
async function notifyBridgeCompat() {
|
||||||
logger.info("checking for bridge...");
|
logger.info("checking for bridge...");
|
||||||
@@ -89,9 +89,8 @@ async function init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If options haven't been set yet, we can't properly
|
* If options haven't been set yet, we can't properly initialize,
|
||||||
* initialize, so wait until init is called again in the
|
* so wait until init is called again in the onInstalled listener.
|
||||||
* onInstalled listener.
|
|
||||||
*/
|
*/
|
||||||
if (!(await options.getAll())) {
|
if (!(await options.getAll())) {
|
||||||
return;
|
return;
|
||||||
@@ -109,9 +108,9 @@ async function init() {
|
|||||||
await initWhitelist();
|
await initWhitelist();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When the browser action is clicked, open a receiver
|
* When the browser action is clicked, open a receiver selector and
|
||||||
* selector and load a sender for the response. The
|
* load a sender for the response. The mirroring sender is loaded
|
||||||
* mirroring sender is loaded into the current tab at the
|
* into the current tab at the
|
||||||
* top-level frame.
|
* top-level frame.
|
||||||
*/
|
*/
|
||||||
browser.browserAction.onClicked.addListener(async tab => {
|
browser.browserAction.onClicked.addListener(async tab => {
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import options from "../lib/options";
|
|||||||
import { stringify } from "../lib/utils";
|
import { stringify } from "../lib/utils";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
ReceiverSelection,
|
||||||
ReceiverSelectionActionType,
|
ReceiverSelectionActionType,
|
||||||
ReceiverSelectorMediaType
|
ReceiverSelectorMediaType
|
||||||
} from "./receiverSelector";
|
} from "./receiverSelector";
|
||||||
@@ -25,12 +26,14 @@ const URL_PATTERNS_ALL = [...URL_PATTERNS_REMOTE, URL_PATTERN_FILE];
|
|||||||
type MenuId = string | number;
|
type MenuId = string | number;
|
||||||
|
|
||||||
let menuIdCast: MenuId;
|
let menuIdCast: MenuId;
|
||||||
let menuIdMediaCast: MenuId;
|
let menuIdCastMedia: MenuId;
|
||||||
let menuIdWhitelist: MenuId;
|
let menuIdWhitelist: MenuId;
|
||||||
let menuIdWhitelistRecommended: MenuId;
|
let menuIdWhitelistRecommended: MenuId;
|
||||||
|
|
||||||
|
/** Match patterns for the whitelist option menus. */
|
||||||
const whitelistChildMenuPatterns = new Map<MenuId, string>();
|
const whitelistChildMenuPatterns = new Map<MenuId, string>();
|
||||||
|
|
||||||
|
/** Handles initial menu setup. */
|
||||||
export async function initMenus() {
|
export async function initMenus() {
|
||||||
logger.info("init (menus)");
|
logger.info("init (menus)");
|
||||||
|
|
||||||
@@ -43,7 +46,7 @@ export async function initMenus() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// <video>/<audio> "Cast..." context menu item
|
// <video>/<audio> "Cast..." context menu item
|
||||||
menuIdMediaCast = browser.menus.create({
|
menuIdCastMedia = browser.menus.create({
|
||||||
contexts: ["audio", "video", "image"],
|
contexts: ["audio", "video", "image"],
|
||||||
title: _("contextCast"),
|
title: _("contextCast"),
|
||||||
visible: opts.mediaEnabled,
|
visible: opts.mediaEnabled,
|
||||||
@@ -67,9 +70,47 @@ export async function initMenus() {
|
|||||||
type: "separator",
|
type: "separator",
|
||||||
parentId: menuIdWhitelist
|
parentId: menuIdWhitelist
|
||||||
});
|
});
|
||||||
|
|
||||||
|
browser.menus.onShown.addListener(onMenuShown);
|
||||||
|
browser.menus.onClicked.addListener(onMenuClicked);
|
||||||
|
|
||||||
|
options.addEventListener("changed", async ev => {
|
||||||
|
const alteredOpts = ev.detail;
|
||||||
|
const newOpts = await options.getAll();
|
||||||
|
|
||||||
|
if (menuIdCastMedia && alteredOpts.includes("mediaEnabled")) {
|
||||||
|
browser.menus.update(menuIdCastMedia, {
|
||||||
|
visible: newOpts.mediaEnabled
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (menuIdCastMedia && alteredOpts.includes("localMediaEnabled")) {
|
||||||
|
browser.menus.update(menuIdCastMedia, {
|
||||||
|
targetUrlPatterns: newOpts.localMediaEnabled
|
||||||
|
? URL_PATTERNS_ALL
|
||||||
|
: URL_PATTERNS_REMOTE
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
browser.menus.onClicked.addListener(async (info, tab) => {
|
/** Handle updating menus when shown. */
|
||||||
|
async function onMenuShown(info: browser.menus._OnShownInfo) {
|
||||||
|
const menuIds = info.menuIds as unknown as number[];
|
||||||
|
|
||||||
|
// Only rebuild menus if whitelist menu present
|
||||||
|
if (menuIds.includes(menuIdWhitelist as number)) {
|
||||||
|
updateWhitelistMenu(info.pageUrl);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Handle menu click events */
|
||||||
|
async function onMenuClicked(
|
||||||
|
info: browser.menus.OnClickData,
|
||||||
|
tab?: browser.tabs.Tab
|
||||||
|
) {
|
||||||
|
// Handle whitelist menus
|
||||||
if (info.parentMenuItemId === menuIdWhitelist) {
|
if (info.parentMenuItemId === menuIdWhitelist) {
|
||||||
const pattern = whitelistChildMenuPatterns.get(info.menuItemId);
|
const pattern = whitelistChildMenuPatterns.get(info.menuItemId);
|
||||||
if (!pattern) {
|
if (!pattern) {
|
||||||
@@ -88,113 +129,81 @@ browser.menus.onClicked.addListener(async (info, tab) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tab?.id === undefined) {
|
// Handle cast menus
|
||||||
throw logger.error("Menu handler tab ID not found.");
|
const castMenuClicked = info.menuItemId === menuIdCast;
|
||||||
}
|
const castMediaMenuClicked = info.menuItemId === menuIdCastMedia;
|
||||||
if (!info.pageUrl) {
|
if (castMenuClicked || castMediaMenuClicked) {
|
||||||
throw logger.error("Menu handler page URL not found.");
|
if (tab?.id === undefined) {
|
||||||
}
|
throw logger.error("Menu handler tab ID not found.");
|
||||||
|
}
|
||||||
|
if (!info.pageUrl) {
|
||||||
|
throw logger.error("Menu handler page URL not found.");
|
||||||
|
}
|
||||||
|
|
||||||
switch (info.menuItemId) {
|
let selection: Nullable<ReceiverSelection> = null;
|
||||||
case menuIdCast: {
|
try {
|
||||||
const selection = await ReceiverSelectorManager.getSelection(
|
selection = await ReceiverSelectorManager.getSelection(
|
||||||
tab.id,
|
tab.id,
|
||||||
info.frameId
|
info.frameId,
|
||||||
|
{ withMediaSender: castMediaMenuClicked }
|
||||||
);
|
);
|
||||||
|
} catch (err) {
|
||||||
|
logger.error("Failed to get receiver selection (cast menu)", err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Invalid selection result
|
||||||
|
if (
|
||||||
|
!selection ||
|
||||||
|
selection.actionType !== ReceiverSelectionActionType.Cast
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Selection cancelled
|
if (castMenuClicked) {
|
||||||
if (!selection) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
CastManager.loadSender({
|
CastManager.loadSender({
|
||||||
tabId: tab.id,
|
tabId: tab.id,
|
||||||
frameId: info.frameId,
|
frameId: info.frameId,
|
||||||
selection
|
selection
|
||||||
});
|
});
|
||||||
|
} else if (castMediaMenuClicked) {
|
||||||
|
/**
|
||||||
|
* If the selected media type is App, that refers to
|
||||||
|
* the media sender in this context, so load media
|
||||||
|
* sender.
|
||||||
|
*/
|
||||||
|
if (selection.mediaType === ReceiverSelectorMediaType.App) {
|
||||||
|
await browser.tabs.executeScript(tab.id, {
|
||||||
|
code: stringify`
|
||||||
|
window.receiver = ${selection.receiverDevice};
|
||||||
|
window.mediaUrl = ${info.srcUrl};
|
||||||
|
window.targetElementId = ${info.targetElementId};
|
||||||
|
`,
|
||||||
|
frameId: info.frameId
|
||||||
|
});
|
||||||
|
|
||||||
break;
|
await browser.tabs.executeScript(tab.id, {
|
||||||
}
|
file: "cast/senders/media/index.js",
|
||||||
|
frameId: info.frameId
|
||||||
case menuIdMediaCast: {
|
});
|
||||||
const selection = await ReceiverSelectorManager.getSelection(
|
} else {
|
||||||
tab.id,
|
// Handle other responses
|
||||||
info.frameId,
|
CastManager.loadSender({
|
||||||
true
|
tabId: tab.id,
|
||||||
);
|
frameId: info.frameId,
|
||||||
|
selection
|
||||||
// Selection cancelled
|
});
|
||||||
if (!selection) {
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (selection.actionType) {
|
|
||||||
case ReceiverSelectionActionType.Cast: {
|
|
||||||
/**
|
|
||||||
* If the selected media type is App, that refers to the
|
|
||||||
* media sender in this context, so load media sender.
|
|
||||||
*/
|
|
||||||
if (selection.mediaType === ReceiverSelectorMediaType.App) {
|
|
||||||
await browser.tabs.executeScript(tab.id, {
|
|
||||||
code: stringify`
|
|
||||||
window.receiver = ${selection.receiverDevice};
|
|
||||||
window.mediaUrl = ${info.srcUrl};
|
|
||||||
window.targetElementId = ${info.targetElementId};
|
|
||||||
`,
|
|
||||||
frameId: info.frameId
|
|
||||||
});
|
|
||||||
|
|
||||||
await browser.tabs.executeScript(tab.id, {
|
|
||||||
file: "cast/senders/media/index.js",
|
|
||||||
frameId: info.frameId
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// Handle other responses
|
|
||||||
CastManager.loadSender({
|
|
||||||
tabId: tab.id,
|
|
||||||
frameId: info.frameId,
|
|
||||||
selection
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
// Hide cast item on extension pages
|
|
||||||
browser.menus.onShown.addListener(info => {
|
|
||||||
if (info.pageUrl?.startsWith(browser.runtime.getURL(""))) {
|
|
||||||
browser.menus.update(menuIdCast, {
|
|
||||||
visible: false
|
|
||||||
});
|
|
||||||
|
|
||||||
browser.menus.refresh();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
browser.menus.onHidden.addListener(() => {
|
|
||||||
browser.menus.update(menuIdCast, {
|
|
||||||
visible: true
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
browser.menus.onShown.addListener(async info => {
|
|
||||||
// Only rebuild menus if whitelist menu present
|
|
||||||
// WebExt typings are broken again here, so ugly casting
|
|
||||||
const menuIds = info.menuIds as unknown as number[];
|
|
||||||
if (!menuIds.includes(menuIdWhitelist as number)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/** Handles updating the whitelist menus for a given URL */
|
||||||
|
async function updateWhitelistMenu(pageUrl?: string) {
|
||||||
/**
|
/**
|
||||||
* If page URL doesn't exist, we're not on a page and have
|
* If page URL doesn't exist, we're not on a page and have nothing
|
||||||
* nothing to whitelist, so disable the menu and return.
|
* to whitelist, so disable the menu and return.
|
||||||
*/
|
*/
|
||||||
if (!info.pageUrl) {
|
if (!pageUrl) {
|
||||||
browser.menus.update(menuIdWhitelist, {
|
browser.menus.update(menuIdWhitelist, {
|
||||||
enabled: false
|
enabled: false
|
||||||
});
|
});
|
||||||
@@ -203,7 +212,7 @@ browser.menus.onShown.addListener(async info => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const url = new URL(info.pageUrl);
|
const url = new URL(pageUrl);
|
||||||
const urlHasOrigin = url.origin !== "null";
|
const urlHasOrigin = url.origin !== "null";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -331,23 +340,4 @@ browser.menus.onShown.addListener(async info => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
await browser.menus.refresh();
|
await browser.menus.refresh();
|
||||||
});
|
}
|
||||||
|
|
||||||
options.addEventListener("changed", async ev => {
|
|
||||||
const alteredOpts = ev.detail;
|
|
||||||
const newOpts = await options.getAll();
|
|
||||||
|
|
||||||
if (menuIdMediaCast && alteredOpts.includes("mediaEnabled")) {
|
|
||||||
browser.menus.update(menuIdMediaCast, {
|
|
||||||
visible: newOpts.mediaEnabled
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (menuIdMediaCast && alteredOpts.includes("localMediaEnabled")) {
|
|
||||||
browser.menus.update(menuIdMediaCast, {
|
|
||||||
targetUrlPatterns: newOpts.localMediaEnabled
|
|
||||||
? URL_PATTERNS_ALL
|
|
||||||
: URL_PATTERNS_REMOTE
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|||||||
@@ -194,7 +194,11 @@ export default class ReceiverSelector extends TypedEventTarget<ReceiverSelectorE
|
|||||||
this.defaultMediaType === undefined ||
|
this.defaultMediaType === undefined ||
|
||||||
this.availableMediaTypes === undefined
|
this.availableMediaTypes === undefined
|
||||||
) {
|
) {
|
||||||
logger.error("Popup receiver data not found.");
|
this.dispatchEvent(
|
||||||
|
new CustomEvent("error", {
|
||||||
|
detail: "Popup receiver data not found."
|
||||||
|
})
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -35,8 +35,8 @@ async function getSelector() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Opens a receiver selector with the specified
|
* Opens a receiver selector with the specified default/available media
|
||||||
* default/available media types.
|
* types.
|
||||||
*
|
*
|
||||||
* Returns a promise that:
|
* Returns a promise that:
|
||||||
* - Resolves to a ReceiverSelection object if selection is
|
* - Resolves to a ReceiverSelection object if selection is
|
||||||
@@ -47,7 +47,7 @@ async function getSelector() {
|
|||||||
async function getSelection(
|
async function getSelection(
|
||||||
contextTabId: number,
|
contextTabId: number,
|
||||||
contextFrameId = 0,
|
contextFrameId = 0,
|
||||||
withMediaSender = false
|
selectionOpts?: { withMediaSender?: boolean }
|
||||||
): Promise<ReceiverSelection | null> {
|
): Promise<ReceiverSelection | null> {
|
||||||
return new Promise(async (resolve, reject) => {
|
return new Promise(async (resolve, reject) => {
|
||||||
let castInstance = CastManager.getInstance(
|
let castInstance = CastManager.getInstance(
|
||||||
@@ -84,7 +84,7 @@ async function getSelection(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Enable app media type if initialized sender app is found
|
// Enable app media type if initialized sender app is found
|
||||||
if (castInstance || withMediaSender) {
|
if (castInstance || selectionOpts?.withMediaSender) {
|
||||||
defaultMediaType = ReceiverSelectorMediaType.App;
|
defaultMediaType = ReceiverSelectorMediaType.App;
|
||||||
availableMediaTypes |= ReceiverSelectorMediaType.App;
|
availableMediaTypes |= ReceiverSelectorMediaType.App;
|
||||||
}
|
}
|
||||||
@@ -193,8 +193,8 @@ async function getSelection(
|
|||||||
|
|
||||||
sharedSelector.addEventListener(
|
sharedSelector.addEventListener(
|
||||||
"error",
|
"error",
|
||||||
storeListener("error", () => {
|
storeListener("error", ev => {
|
||||||
reject();
|
reject(ev.detail);
|
||||||
removeListeners();
|
removeListeners();
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -25,10 +25,7 @@ export interface CastInstance {
|
|||||||
appId?: string;
|
appId?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Keeps track of cast API instances and provides bridge messaging. */
|
||||||
* Keeps track of cast API instances and provides bridge
|
|
||||||
* messaging.
|
|
||||||
*/
|
|
||||||
export default new (class CastManager {
|
export default new (class CastManager {
|
||||||
private activeInstances = new Set<CastInstance>();
|
private activeInstances = new Set<CastInstance>();
|
||||||
|
|
||||||
@@ -60,8 +57,7 @@ export default new (class CastManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds a cast instance at the given tab (and optionally
|
* Finds a cast instance at the given tab (and optionally frame) ID.
|
||||||
* frame) ID.
|
|
||||||
*/
|
*/
|
||||||
public getInstance(tabId: number, frameId?: number) {
|
public getInstance(tabId: number, frameId?: number) {
|
||||||
for (const instance of this.activeInstances) {
|
for (const instance of this.activeInstances) {
|
||||||
@@ -77,8 +73,8 @@ export default new (class CastManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a cast instance with a given port and connects
|
* Creates a cast instance with a given port and connects messaging
|
||||||
* messaging correctly depending on the type of port.
|
* correctly depending on the type of port.
|
||||||
*/
|
*/
|
||||||
public async createInstance(port: AnyPort) {
|
public async createInstance(port: AnyPort) {
|
||||||
const instance = await (port instanceof MessagePort
|
const instance = await (port instanceof MessagePort
|
||||||
@@ -95,9 +91,7 @@ export default new (class CastManager {
|
|||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Creates a cast instance with a `MessagePort` content port. */
|
||||||
* Creates a cast instance with a `MessagePort` content port.
|
|
||||||
*/
|
|
||||||
private async createInstanceFromBackground(
|
private async createInstanceFromBackground(
|
||||||
contentPort: MessagePort
|
contentPort: MessagePort
|
||||||
): Promise<CastInstance> {
|
): Promise<CastInstance> {
|
||||||
@@ -125,8 +119,7 @@ export default new (class CastManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a cast instance with a WebExtension `Port` content
|
* Creates a cast instance with a WebExtension `Port` content port.
|
||||||
* port.
|
|
||||||
*/
|
*/
|
||||||
private async createInstanceFromContent(
|
private async createInstanceFromContent(
|
||||||
contentPort: Port
|
contentPort: Port
|
||||||
@@ -191,9 +184,9 @@ export default new (class CastManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle content messages from the cast instance. These will
|
* Handle content messages from the cast instance. These will either
|
||||||
* either be handled here in the background script or forwarded
|
* be handled here in the background script or forwarded to the
|
||||||
* to the bridge associated with the cast instance.
|
* bridge associated with the cast instance.
|
||||||
*/
|
*/
|
||||||
private async handleContentMessage(
|
private async handleContentMessage(
|
||||||
instance: CastInstance,
|
instance: CastInstance,
|
||||||
@@ -249,9 +242,10 @@ export default new (class CastManager {
|
|||||||
switch (selection.actionType) {
|
switch (selection.actionType) {
|
||||||
case ReceiverSelectionActionType.Cast: {
|
case ReceiverSelectionActionType.Cast: {
|
||||||
/**
|
/**
|
||||||
* If the media type returned from the selector has
|
* If the media type returned from the
|
||||||
* been changed, we need to cancel the current
|
* selector has been changed, we need to
|
||||||
* sender and switch it out for the right one.
|
* cancel the current sender and switch it
|
||||||
|
* out for the right one.
|
||||||
*/
|
*/
|
||||||
if (
|
if (
|
||||||
selection.mediaType !==
|
selection.mediaType !==
|
||||||
@@ -298,8 +292,8 @@ export default new (class CastManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO: If we're closing a selector, make sure it's the same
|
* TODO: If we're closing a selector, make sure it's the
|
||||||
* one that caused the session creation.
|
* same one that caused the session creation.
|
||||||
*/
|
*/
|
||||||
case "main:closeReceiverSelector": {
|
case "main:closeReceiverSelector": {
|
||||||
const selector = await ReceiverSelectorManager.getSelector();
|
const selector = await ReceiverSelectorManager.getSelector();
|
||||||
@@ -317,8 +311,8 @@ export default new (class CastManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads the appropriate sender for a given receiver
|
* Loads the appropriate sender for a given receiver selector
|
||||||
* selector response.
|
* response.
|
||||||
*/
|
*/
|
||||||
public async loadSender(opts: {
|
public async loadSender(opts: {
|
||||||
tabId: number;
|
tabId: number;
|
||||||
|
|||||||
@@ -45,9 +45,8 @@ enum _MediaCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Takes a media object and a media status object and merges
|
* Takes a media object and a media status object and merges the status
|
||||||
* the status with the existing media object, updating it with
|
* with the existing media object, updating it with new properties.
|
||||||
* new properties.
|
|
||||||
*/
|
*/
|
||||||
function updateMedia(media: Media, status: MediaStatus) {
|
function updateMedia(media: Media, status: MediaStatus) {
|
||||||
if (status.currentTime) {
|
if (status.currentTime) {
|
||||||
@@ -179,7 +178,7 @@ export default class Session {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends a media message to the app receiver.
|
* Sends a media message to the app receiver.
|
||||||
* urn:x-cast:com.google.cast.media
|
* `urn:x-cast:com.google.cast.media`
|
||||||
*/
|
*/
|
||||||
#sendMediaMessage = (
|
#sendMediaMessage = (
|
||||||
message: DistributiveOmit<SenderMediaMessage, "requestId">
|
message: DistributiveOmit<SenderMediaMessage, "requestId">
|
||||||
|
|||||||
Reference in New Issue
Block a user