mirror of
https://github.com/hensm/fx_cast.git
synced 2026-06-08 08:39:59 +00:00
Replace StatusManager
This commit is contained in:
@@ -27,7 +27,7 @@
|
|||||||
, "comma-style": [ "error", "first" ]
|
, "comma-style": [ "error", "first" ]
|
||||||
, "no-multiple-empty-lines": [ "error", { "max": 2 }]
|
, "no-multiple-empty-lines": [ "error", { "max": 2 }]
|
||||||
, "no-console": [ "error", {
|
, "no-console": [ "error", {
|
||||||
"allow": [ "info", "error" ]
|
"allow": [ "info", "warn", "error" ]
|
||||||
}]
|
}]
|
||||||
, "operator-linebreak": [ "error", "after", {
|
, "operator-linebreak": [ "error", "after", {
|
||||||
"overrides": {
|
"overrides": {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import castv2 from "castv2";
|
|||||||
|
|
||||||
import Session, { NS_CONNECTION, NS_RECEIVER } from "./Session";
|
import Session, { NS_CONNECTION, NS_RECEIVER } from "./Session";
|
||||||
import Media from "./Media";
|
import Media from "./Media";
|
||||||
import { Receiver } from "../../types";
|
import { ReceiverDevice } from "../../types";
|
||||||
|
|
||||||
|
|
||||||
// Existing counterpart Media/Session objects
|
// Existing counterpart Media/Session objects
|
||||||
|
|||||||
@@ -2,10 +2,13 @@
|
|||||||
|
|
||||||
import mdns from "mdns";
|
import mdns from "mdns";
|
||||||
|
|
||||||
import StatusListener from "./chromecast/StatusListener";
|
|
||||||
import { ReceiverStatus } from "../types";
|
|
||||||
import { sendMessage } from "../lib/nativeMessaging";
|
import { sendMessage } from "../lib/nativeMessaging";
|
||||||
|
|
||||||
|
import { ReceiverStatus } from "../types";
|
||||||
|
import { Message } from "../messaging";
|
||||||
|
|
||||||
|
import StatusListener from "./chromecast/StatusListener";
|
||||||
|
|
||||||
|
|
||||||
interface CastTxtRecord {
|
interface CastTxtRecord {
|
||||||
id: string; cd: string; rm: string;
|
id: string; cd: string; rm: string;
|
||||||
@@ -34,12 +37,14 @@ function onBrowserServiceUp(service: mdns.Service) {
|
|||||||
const txtRecord = service.txtRecord as CastTxtRecord;
|
const txtRecord = service.txtRecord as CastTxtRecord;
|
||||||
|
|
||||||
sendMessage({
|
sendMessage({
|
||||||
subject: "main:serviceUp"
|
subject: "main:receiverDeviceUp"
|
||||||
, data: {
|
, data: {
|
||||||
host: service.addresses[0]
|
receiverDevice: {
|
||||||
, port: service.port
|
host: service.addresses[0]
|
||||||
, id: txtRecord.id
|
, port: service.port
|
||||||
, friendlyName: txtRecord.fn
|
, id: txtRecord.id
|
||||||
|
, friendlyName: txtRecord.fn
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -72,41 +77,20 @@ export function startDiscovery(options: InitializeOptions) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { id } = service.txtRecord;
|
|
||||||
|
|
||||||
const listener = new StatusListener(
|
const listener = new StatusListener(
|
||||||
service.addresses[0]
|
service.addresses[0], service.port);
|
||||||
, service.port);
|
|
||||||
|
|
||||||
listener.on("receiverStatus", (status: ReceiverStatus) => {
|
listener.on("receiverStatus", (status: ReceiverStatus) => {
|
||||||
const receiverStatusMessage: any = {
|
sendMessage({
|
||||||
subject: "main:updateReceiverStatus"
|
subject: "main:receiverDeviceUpdated"
|
||||||
, data: {
|
, data: {
|
||||||
id
|
receiverDeviceId: service.txtRecord.id
|
||||||
, status: {
|
, status
|
||||||
volume: {
|
|
||||||
level: status.volume.level
|
|
||||||
, muted: status.volume.muted
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
if (status.applications && status.applications.length) {
|
|
||||||
const application = status.applications[0];
|
|
||||||
|
|
||||||
receiverStatusMessage.data.status.application = {
|
|
||||||
appId: application.appId
|
|
||||||
, displayName: application.displayName
|
|
||||||
, isIdleScreen: application.isIdleScreen
|
|
||||||
, statusText: application.statusText
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
sendMessage(receiverStatusMessage);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
statusListeners.set(id, listener);
|
statusListeners.set(service.txtRecord.id, listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
function onStatusBrowserServiceDown(_service: mdns.Service) {
|
function onStatusBrowserServiceDown(_service: mdns.Service) {
|
||||||
|
|||||||
@@ -51,8 +51,8 @@ decodeTransform.on("data", (message: Message) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case "bridge:stopReceiverApp": {
|
case "bridge:stopReceiverApp": {
|
||||||
const { host, port } = message.data.receiver;
|
const { receiverDevice } = message.data;
|
||||||
stopReceiverApp(host, port);
|
stopReceiverApp(receiverDevice.host, receiverDevice.port);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
import { Receiver
|
import { ReceiverDevice
|
||||||
, ReceiverSelectionCast
|
, ReceiverSelectionCast
|
||||||
, ReceiverSelectionStop
|
, ReceiverSelectionStop
|
||||||
, ReceiverStatus } from "./types";
|
, ReceiverStatus } from "./types";
|
||||||
@@ -127,7 +127,7 @@ type MessageDefinitions = {
|
|||||||
, "bridge:openReceiverSelector": string
|
, "bridge:openReceiverSelector": string
|
||||||
, "bridge:closeReceiverSelector": {}
|
, "bridge:closeReceiverSelector": {}
|
||||||
|
|
||||||
, "bridge:stopReceiverApp": { receiver: Receiver }
|
, "bridge:stopReceiverApp": { receiverDevice: ReceiverDevice }
|
||||||
|
|
||||||
|
|
||||||
, "bridge:startMediaServer": {
|
, "bridge:startMediaServer": {
|
||||||
@@ -145,13 +145,21 @@ type MessageDefinitions = {
|
|||||||
, "mediaCast:mediaServerError": {}
|
, "mediaCast:mediaServerError": {}
|
||||||
|
|
||||||
|
|
||||||
, "main:serviceUp": Receiver
|
, "main:serviceUp": ReceiverDevice
|
||||||
, "main:serviceDown": { id: string }
|
, "main:serviceDown": { id: string }
|
||||||
|
|
||||||
, "main:updateReceiverStatus": {
|
, "main:updateReceiverStatus": {
|
||||||
id: string
|
id: string
|
||||||
, status: ReceiverStatus
|
, status: ReceiverStatus
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
, "main:receiverDeviceUp": { receiverDevice: ReceiverDevice }
|
||||||
|
, "main:receiverDeviceDown": { receiverDeviceId: string }
|
||||||
|
, "main:receiverDeviceUpdated": {
|
||||||
|
receiverDeviceId: string
|
||||||
|
, status: ReceiverStatus
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ export interface ReceiverStatus {
|
|||||||
, transportId: string
|
, transportId: string
|
||||||
, universalAppId: string
|
, universalAppId: string
|
||||||
}>
|
}>
|
||||||
, isActiveInput: boolean
|
, isActiveInput?: boolean
|
||||||
, isStandBy: boolean
|
, isStandBy?: boolean
|
||||||
, userEq: unknown
|
, userEq: unknown
|
||||||
, volume: Volume
|
, volume: Volume
|
||||||
}
|
}
|
||||||
@@ -68,17 +68,17 @@ export enum ReceiverSelectionActionType {
|
|||||||
|
|
||||||
export interface ReceiverSelectionCast {
|
export interface ReceiverSelectionCast {
|
||||||
actionType: ReceiverSelectionActionType.Cast;
|
actionType: ReceiverSelectionActionType.Cast;
|
||||||
receiver: Receiver;
|
receiver: ReceiverDevice;
|
||||||
mediaType: ReceiverSelectorMediaType;
|
mediaType: ReceiverSelectorMediaType;
|
||||||
filePath?: string;
|
filePath?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ReceiverSelectionStop {
|
export interface ReceiverSelectionStop {
|
||||||
actionType: ReceiverSelectionActionType.Stop;
|
actionType: ReceiverSelectionActionType.Stop;
|
||||||
receiver: Receiver;
|
receiver: ReceiverDevice;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Receiver {
|
export interface ReceiverDevice {
|
||||||
host: string;
|
host: string;
|
||||||
friendlyName: string;
|
friendlyName: string;
|
||||||
id: string;
|
id: string;
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import { ReceiverSelectionActionType
|
|||||||
import ReceiverSelectorManager
|
import ReceiverSelectorManager
|
||||||
from "./receiverSelector/ReceiverSelectorManager";
|
from "./receiverSelector/ReceiverSelectorManager";
|
||||||
|
|
||||||
import StatusManager from "./StatusManager";
|
import receiverDevices from "./receiverDevices";
|
||||||
|
|
||||||
|
|
||||||
type AnyPort = Port | MessagePort;
|
type AnyPort = Port | MessagePort;
|
||||||
@@ -37,20 +37,20 @@ export default new class ShimManager {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
StatusManager.addEventListener("serviceUp", ev => {
|
receiverDevices.addEventListener("receiverDeviceUp", ev => {
|
||||||
for (const shim of this.activeShims) {
|
for (const shim of this.activeShims) {
|
||||||
shim.contentPort.postMessage({
|
shim.contentPort.postMessage({
|
||||||
subject: "shim:serviceUp"
|
subject: "shim:serviceUp"
|
||||||
, data: { id: ev.detail.id }
|
, data: { id: ev.detail.receiverDevice.id }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
StatusManager.addEventListener("serviceDown", ev => {
|
receiverDevices.addEventListener("receiverDeviceDown", ev => {
|
||||||
for (const shim of this.activeShims) {
|
for (const shim of this.activeShims) {
|
||||||
shim.contentPort.postMessage({
|
shim.contentPort.postMessage({
|
||||||
subject: "shim:serviceDown"
|
subject: "shim:serviceDown"
|
||||||
, data: { id: ev.detail.id }
|
, data: { id: ev.detail.receiverDeviceId }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -170,10 +170,10 @@ export default new class ShimManager {
|
|||||||
case "main:shimReady": {
|
case "main:shimReady": {
|
||||||
shim.appId = message.data.appId;
|
shim.appId = message.data.appId;
|
||||||
|
|
||||||
for (const receiver of StatusManager.getReceivers()) {
|
for (const receiverDevice of receiverDevices.getDevices()) {
|
||||||
shim.contentPort.postMessage({
|
shim.contentPort.postMessage({
|
||||||
subject: "shim:serviceUp"
|
subject: "shim:serviceUp"
|
||||||
, data: { id: receiver.id }
|
, data: { id: receiverDevice.id }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,163 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
|
|
||||||
import bridge from "../lib/bridge";
|
|
||||||
import logger from "../lib/logger";
|
|
||||||
import { Message, Port } from "../messaging";
|
|
||||||
|
|
||||||
import { TypedEventTarget } from "../lib/TypedEventTarget";
|
|
||||||
import { Receiver, ReceiverStatus } from "../types";
|
|
||||||
|
|
||||||
|
|
||||||
interface EventMap {
|
|
||||||
"serviceUp": Receiver;
|
|
||||||
"serviceDown": { id: string };
|
|
||||||
"statusUpdate": { id: string, status: ReceiverStatus };
|
|
||||||
}
|
|
||||||
|
|
||||||
export default new class StatusManager
|
|
||||||
extends TypedEventTarget<EventMap> {
|
|
||||||
|
|
||||||
private bridgePort: (Port | null) = null;
|
|
||||||
private receivers = new Map<string, Receiver>();
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
|
|
||||||
// Bind listeners
|
|
||||||
this.onBridgePortMessage = this.onBridgePortMessage.bind(this);
|
|
||||||
this.onBridgePortDisconnect = this.onBridgePortDisconnect.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async init() {
|
|
||||||
if (!this.bridgePort) {
|
|
||||||
this.bridgePort = await this.createBridgePort();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public *getReceivers() {
|
|
||||||
for (const [ , receiver ] of this.receivers) {
|
|
||||||
if (receiver.status && receiver.status.application
|
|
||||||
&& receiver.status.volume) {
|
|
||||||
yield receiver;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async stopReceiverApp(receiver: Receiver) {
|
|
||||||
if (!this.bridgePort) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.bridgePort.postMessage({
|
|
||||||
subject: "bridge:stopReceiverApp"
|
|
||||||
, data: { receiver }
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private async createBridgePort() {
|
|
||||||
const bridgePort = await bridge.connect();
|
|
||||||
bridgePort.onMessage.addListener(this.onBridgePortMessage);
|
|
||||||
bridgePort.onDisconnect.addListener(this.onBridgePortDisconnect);
|
|
||||||
|
|
||||||
bridgePort.postMessage({
|
|
||||||
subject: "bridge:initialize"
|
|
||||||
, data: {
|
|
||||||
shouldWatchStatus: true
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return bridgePort;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles incoming bridge status messages, manages the
|
|
||||||
* receiver list, and dispatches events.
|
|
||||||
*/
|
|
||||||
private onBridgePortMessage(message: Message) {
|
|
||||||
switch (message.subject) {
|
|
||||||
case "main:serviceUp": {
|
|
||||||
const { data: receiver } = message;
|
|
||||||
this.receivers.set(receiver.id, receiver);
|
|
||||||
|
|
||||||
this.dispatchEvent(new CustomEvent("serviceUp", {
|
|
||||||
detail: receiver
|
|
||||||
}));
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case "main:serviceDown": {
|
|
||||||
const { data: { id }} = message;
|
|
||||||
|
|
||||||
if (this.receivers.has(id)) {
|
|
||||||
this.receivers.delete(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.dispatchEvent(new CustomEvent("serviceDown", {
|
|
||||||
detail: { id }
|
|
||||||
}));
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case "main:updateReceiverStatus": {
|
|
||||||
const { data: { id, status }} = message;
|
|
||||||
const receiver = this.receivers.get(id);
|
|
||||||
|
|
||||||
if (!receiver) {
|
|
||||||
throw logger.error(`Could not find receiver (${id}) specified in status message.`);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Merge with existing
|
|
||||||
this.receivers.set(id, {
|
|
||||||
...receiver
|
|
||||||
, status: {
|
|
||||||
...receiver.status
|
|
||||||
, ...status
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.dispatchEvent(new CustomEvent("statusUpdate", {
|
|
||||||
detail: { id, status }
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Runs once the status bridge has disconnected. Sends
|
|
||||||
* serviceDown messages for all receivers to all shims to
|
|
||||||
* update receiver availability, then clears the receiver
|
|
||||||
* list.
|
|
||||||
*
|
|
||||||
* Attempts to reinitialize the status bridge after 10
|
|
||||||
* seconds. If it fails immediately, this handler will be
|
|
||||||
* triggered again and the timer is reset for another 10
|
|
||||||
* seconds.
|
|
||||||
*/
|
|
||||||
private onBridgePortDisconnect() {
|
|
||||||
for (const [ , receiver ] of this.receivers) {
|
|
||||||
const serviceDownEvent = new CustomEvent("serviceDown", {
|
|
||||||
detail: { id: receiver.id }
|
|
||||||
});
|
|
||||||
|
|
||||||
this.dispatchEvent(serviceDownEvent);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cleanup
|
|
||||||
this.receivers.clear();
|
|
||||||
|
|
||||||
if (this.bridgePort) {
|
|
||||||
this.bridgePort.onDisconnect.removeListener(
|
|
||||||
this.onBridgePortDisconnect);
|
|
||||||
this.bridgePort.onMessage.removeListener(
|
|
||||||
this.onBridgePortMessage);
|
|
||||||
|
|
||||||
this.bridgePort = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
window.setTimeout(async () => {
|
|
||||||
this.bridgePort = await this.createBridgePort();
|
|
||||||
}, 10000);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -11,7 +11,8 @@ import ReceiverSelectorManager
|
|||||||
from "./receiverSelector/ReceiverSelectorManager";
|
from "./receiverSelector/ReceiverSelectorManager";
|
||||||
|
|
||||||
import ShimManager from "./ShimManager";
|
import ShimManager from "./ShimManager";
|
||||||
import StatusManager from "./StatusManager";
|
|
||||||
|
import receiverDevices from "./receiverDevices";
|
||||||
|
|
||||||
import { initMenus } from "./menus";
|
import { initMenus } from "./menus";
|
||||||
import { initWhitelist } from "./whitelist";
|
import { initWhitelist } from "./whitelist";
|
||||||
@@ -155,7 +156,7 @@ async function init() {
|
|||||||
|
|
||||||
await notifyBridgeCompat();
|
await notifyBridgeCompat();
|
||||||
|
|
||||||
await StatusManager.init();
|
await receiverDevices.init();
|
||||||
await ShimManager.init();
|
await ShimManager.init();
|
||||||
|
|
||||||
await initMenus();
|
await initMenus();
|
||||||
|
|||||||
167
ext/src/background/receiverDevices.ts
Normal file
167
ext/src/background/receiverDevices.ts
Normal file
@@ -0,0 +1,167 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
import bridge from "../lib/bridge";
|
||||||
|
import logger from "../lib/logger";
|
||||||
|
import { TypedEventTarget } from "../lib/TypedEventTarget";
|
||||||
|
|
||||||
|
import messaging, { Message, Port } from "../messaging";
|
||||||
|
import { ReceiverDevice, ReceiverStatus } from "../types";
|
||||||
|
|
||||||
|
|
||||||
|
interface EventMap {
|
||||||
|
"receiverDeviceUp": { receiverDevice: ReceiverDevice }
|
||||||
|
, "receiverDeviceDown": { receiverDeviceId: string }
|
||||||
|
, "receiverDeviceUpdated": {
|
||||||
|
receiverDeviceId: string
|
||||||
|
, status: ReceiverStatus
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default new class extends TypedEventTarget<EventMap> {
|
||||||
|
/**
|
||||||
|
* Map of receiver device IDs to devices. Updated as
|
||||||
|
* receiverDevice messages are received from the bridge.
|
||||||
|
*/
|
||||||
|
private receiverDevices = new Map<string, ReceiverDevice>();
|
||||||
|
|
||||||
|
private bridgePort?: Port;
|
||||||
|
|
||||||
|
|
||||||
|
async init() {
|
||||||
|
if (!this.bridgePort) {
|
||||||
|
await this.refresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize (or re-initialize) a bridge connection to
|
||||||
|
* start dispatching events.
|
||||||
|
*/
|
||||||
|
async refresh() {
|
||||||
|
this.bridgePort?.disconnect();
|
||||||
|
|
||||||
|
const port = await bridge.connect();
|
||||||
|
|
||||||
|
port.onMessage.addListener(this.onBridgeMessage);
|
||||||
|
port.onDisconnect.addListener(this.onBridgeDisconnect);
|
||||||
|
|
||||||
|
port.postMessage({
|
||||||
|
subject: "bridge:initialize"
|
||||||
|
, data: {
|
||||||
|
// Also send back status messages
|
||||||
|
shouldWatchStatus: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.bridgePort = port;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a list of receiver devices
|
||||||
|
*/
|
||||||
|
getDevices() {
|
||||||
|
return Array.from(this.receiverDevices.values());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stops a receiver app running on a given device.
|
||||||
|
*/
|
||||||
|
stopReceiverApp(receiverDeviceId: string) {
|
||||||
|
if (!this.bridgePort) {
|
||||||
|
logger.error("Failed to stop receiver device, no bridge connection");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const receiverDevice = this.receiverDevices.get(receiverDeviceId);
|
||||||
|
if (receiverDevice) {
|
||||||
|
this.bridgePort.postMessage({
|
||||||
|
subject: "bridge:stopReceiverApp"
|
||||||
|
, data: { receiverDevice }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private onBridgeMessage = (message: Message) => {
|
||||||
|
switch (message.subject) {
|
||||||
|
case "main:receiverDeviceUp": {
|
||||||
|
const { receiverDevice } = message.data;
|
||||||
|
|
||||||
|
this.receiverDevices.set(receiverDevice.id, receiverDevice);
|
||||||
|
this.dispatchEvent(
|
||||||
|
new CustomEvent("receiverDeviceUp"
|
||||||
|
, {
|
||||||
|
detail: { receiverDevice }
|
||||||
|
}));
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case "main:receiverDeviceDown": {
|
||||||
|
const { receiverDeviceId } = message.data;
|
||||||
|
|
||||||
|
if (this.receiverDevices.has(receiverDeviceId)) {
|
||||||
|
this.receiverDevices.delete(receiverDeviceId);
|
||||||
|
}
|
||||||
|
this.dispatchEvent(
|
||||||
|
new CustomEvent("receiverDeviceDown"
|
||||||
|
, {
|
||||||
|
detail: { receiverDeviceId }
|
||||||
|
}));
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case "main:receiverDeviceUpdated": {
|
||||||
|
const { receiverDeviceId, status } = message.data;
|
||||||
|
const receiverDevice =
|
||||||
|
this.receiverDevices.get(receiverDeviceId);
|
||||||
|
|
||||||
|
if (!receiverDevice) {
|
||||||
|
logger.error(`Receiver ID \`${receiverDeviceId}\` not found!`);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (receiverDevice.status) {
|
||||||
|
receiverDevice.status.isActiveInput = status.isActiveInput;
|
||||||
|
receiverDevice.status.isStandBy = status.isStandBy;
|
||||||
|
receiverDevice.status.userEq = status.userEq;
|
||||||
|
receiverDevice.status.volume = status.volume;
|
||||||
|
|
||||||
|
if (status.applications) {
|
||||||
|
receiverDevice.status.applications =
|
||||||
|
status.applications;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
receiverDevice.status = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.dispatchEvent(
|
||||||
|
new CustomEvent("receiverDeviceUpdated"
|
||||||
|
, {
|
||||||
|
detail: {
|
||||||
|
receiverDeviceId
|
||||||
|
, status: receiverDevice.status
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private onBridgeDisconnect = () => {
|
||||||
|
// Notify listeners of device availablility
|
||||||
|
for (const [ , receiverDevice ] of this.receiverDevices) {
|
||||||
|
const event = new CustomEvent("receiverDeviceDown", {
|
||||||
|
detail: { receiverDeviceId: receiverDevice.id }
|
||||||
|
});
|
||||||
|
|
||||||
|
this.dispatchEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.receiverDevices.clear();
|
||||||
|
|
||||||
|
// Re-initialize after 10 seconds
|
||||||
|
window.setTimeout(() => {
|
||||||
|
this.refresh();
|
||||||
|
}, 10000);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -8,7 +8,7 @@ import options from "../../lib/options";
|
|||||||
|
|
||||||
import { TypedEventTarget } from "../../lib/TypedEventTarget";
|
import { TypedEventTarget } from "../../lib/TypedEventTarget";
|
||||||
import { getWindowCenteredProps } from "../../lib/utils";
|
import { getWindowCenteredProps } from "../../lib/utils";
|
||||||
import { Receiver } from "../../types";
|
import { ReceiverDevice } from "../../types";
|
||||||
|
|
||||||
import ReceiverSelector, {
|
import ReceiverSelector, {
|
||||||
ReceiverSelection
|
ReceiverSelection
|
||||||
@@ -34,7 +34,7 @@ export default class NativeReceiverSelector extends ReceiverSelector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async open(
|
public async open(
|
||||||
receivers: Receiver[]
|
receivers: ReceiverDevice[]
|
||||||
, defaultMediaType: ReceiverSelectorMediaType
|
, defaultMediaType: ReceiverSelectorMediaType
|
||||||
, availableMediaTypes: ReceiverSelectorMediaType
|
, availableMediaTypes: ReceiverSelectorMediaType
|
||||||
, appId?: string): Promise<void> {
|
, appId?: string): Promise<void> {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import options from "../../lib/options";
|
|||||||
|
|
||||||
import { TypedEventTarget } from "../../lib/TypedEventTarget";
|
import { TypedEventTarget } from "../../lib/TypedEventTarget";
|
||||||
import { getWindowCenteredProps, WindowCenteredProps } from "../../lib/utils";
|
import { getWindowCenteredProps, WindowCenteredProps } from "../../lib/utils";
|
||||||
import { Receiver } from "../../types";
|
import { ReceiverDevice } from "../../types";
|
||||||
|
|
||||||
|
|
||||||
const POPUP_URL = browser.runtime.getURL("ui/popup/index.html");
|
const POPUP_URL = browser.runtime.getURL("ui/popup/index.html");
|
||||||
@@ -20,7 +20,7 @@ export default class PopupReceiverSelector extends ReceiverSelector {
|
|||||||
private messagePort?: Port;
|
private messagePort?: Port;
|
||||||
private messagePortDisconnected?: boolean;
|
private messagePortDisconnected?: boolean;
|
||||||
|
|
||||||
private receivers?: Receiver[];
|
private receivers?: ReceiverDevice[];
|
||||||
private defaultMediaType?: ReceiverSelectorMediaType;
|
private defaultMediaType?: ReceiverSelectorMediaType;
|
||||||
private availableMediaTypes?: ReceiverSelectorMediaType;
|
private availableMediaTypes?: ReceiverSelectorMediaType;
|
||||||
|
|
||||||
@@ -53,7 +53,7 @@ export default class PopupReceiverSelector extends ReceiverSelector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async open(
|
public async open(
|
||||||
receivers: Receiver[]
|
receivers: ReceiverDevice[]
|
||||||
, defaultMediaType: ReceiverSelectorMediaType
|
, defaultMediaType: ReceiverSelectorMediaType
|
||||||
, availableMediaTypes: ReceiverSelectorMediaType
|
, availableMediaTypes: ReceiverSelectorMediaType
|
||||||
, appId?: string): Promise<void> {
|
, appId?: string): Promise<void> {
|
||||||
@@ -115,7 +115,7 @@ export default class PopupReceiverSelector extends ReceiverSelector {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public update(receivers: Receiver[]) {
|
public update(receivers: ReceiverDevice[]) {
|
||||||
this.receivers = receivers;
|
this.receivers = receivers;
|
||||||
this.messagePort?.postMessage({
|
this.messagePort?.postMessage({
|
||||||
subject: "popup:update"
|
subject: "popup:update"
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
import { TypedEventTarget } from "../../lib/TypedEventTarget";
|
import { TypedEventTarget } from "../../lib/TypedEventTarget";
|
||||||
import { Receiver } from "../../types";
|
import { ReceiverDevice } from "../../types";
|
||||||
|
|
||||||
|
|
||||||
export enum ReceiverSelectorMediaType {
|
export enum ReceiverSelectorMediaType {
|
||||||
@@ -18,13 +18,13 @@ export enum ReceiverSelectionActionType {
|
|||||||
|
|
||||||
export interface ReceiverSelectionCast {
|
export interface ReceiverSelectionCast {
|
||||||
actionType: ReceiverSelectionActionType.Cast;
|
actionType: ReceiverSelectionActionType.Cast;
|
||||||
receiver: Receiver;
|
receiver: ReceiverDevice;
|
||||||
mediaType: ReceiverSelectorMediaType;
|
mediaType: ReceiverSelectorMediaType;
|
||||||
filePath?: string;
|
filePath?: string;
|
||||||
}
|
}
|
||||||
export interface ReceiverSelectionStop {
|
export interface ReceiverSelectionStop {
|
||||||
actionType: ReceiverSelectionActionType.Stop;
|
actionType: ReceiverSelectionActionType.Stop;
|
||||||
receiver: Receiver;
|
receiver: ReceiverDevice;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ReceiverSelection = ReceiverSelectionCast | ReceiverSelectionStop;
|
export type ReceiverSelection = ReceiverSelectionCast | ReceiverSelectionStop;
|
||||||
@@ -43,12 +43,12 @@ export default abstract class ReceiverSelector
|
|||||||
abstract readonly isOpen: boolean;
|
abstract readonly isOpen: boolean;
|
||||||
|
|
||||||
abstract open (
|
abstract open (
|
||||||
receivers: Receiver[]
|
receivers: ReceiverDevice[]
|
||||||
, defaultMediaType: ReceiverSelectorMediaType
|
, defaultMediaType: ReceiverSelectorMediaType
|
||||||
, availableMediaTypes: ReceiverSelectorMediaType
|
, availableMediaTypes: ReceiverSelectorMediaType
|
||||||
, appId?: string): void;
|
, appId?: string): void;
|
||||||
|
|
||||||
abstract update (receivers: Receiver[]): void;
|
abstract update (receivers: ReceiverDevice[]): void;
|
||||||
|
|
||||||
abstract close (): void;
|
abstract close (): void;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import options from "../../lib/options";
|
|||||||
import logger from "../../lib/logger";
|
import logger from "../../lib/logger";
|
||||||
|
|
||||||
import ShimManager from "../ShimManager";
|
import ShimManager from "../ShimManager";
|
||||||
import StatusManager from "../StatusManager";
|
import receiverDevices from "../receiverDevices";
|
||||||
|
|
||||||
import { getMediaTypesForPageUrl } from "../../lib/utils";
|
import { getMediaTypesForPageUrl } from "../../lib/utils";
|
||||||
|
|
||||||
@@ -120,12 +120,15 @@ async function getSelection(
|
|||||||
|
|
||||||
|
|
||||||
function onReceiverChange() {
|
function onReceiverChange() {
|
||||||
sharedSelector.update(Array.from(StatusManager.getReceivers()));
|
sharedSelector.update(receiverDevices.getDevices());
|
||||||
}
|
}
|
||||||
|
|
||||||
StatusManager.addEventListener("serviceUp", onReceiverChange);
|
receiverDevices.addEventListener(
|
||||||
StatusManager.addEventListener("serviceDown", onReceiverChange);
|
"receiverDeviceUp", onReceiverChange);
|
||||||
StatusManager.addEventListener("statusUpdate", onReceiverChange);
|
receiverDevices.addEventListener(
|
||||||
|
"receiverDeviceDown", onReceiverChange);
|
||||||
|
receiverDevices.addEventListener(
|
||||||
|
"receiverDeviceUpdated", onReceiverChange);
|
||||||
|
|
||||||
|
|
||||||
let onSelected: any;
|
let onSelected: any;
|
||||||
@@ -156,9 +159,12 @@ async function getSelection(
|
|||||||
sharedSelector.removeEventListener("error", onError);
|
sharedSelector.removeEventListener("error", onError);
|
||||||
sharedSelector.removeEventListener("stop", onStop);
|
sharedSelector.removeEventListener("stop", onStop);
|
||||||
|
|
||||||
StatusManager.removeEventListener("serviceUp", onReceiverChange);
|
receiverDevices.removeEventListener(
|
||||||
StatusManager.removeEventListener("serviceDown", onReceiverChange);
|
"receiverDeviceUp", onReceiverChange);
|
||||||
StatusManager.removeEventListener("statusUpdate", onReceiverChange);
|
receiverDevices.removeEventListener(
|
||||||
|
"receiverDeviceDown", onReceiverChange);
|
||||||
|
receiverDevices.removeEventListener(
|
||||||
|
"receiverDeviceUpdated", onReceiverChange);
|
||||||
}
|
}
|
||||||
|
|
||||||
sharedSelector.addEventListener("selected"
|
sharedSelector.addEventListener("selected"
|
||||||
@@ -191,10 +197,9 @@ async function getSelection(
|
|||||||
sharedSelector.addEventListener("stop"
|
sharedSelector.addEventListener("stop"
|
||||||
, storeListener("stop", async ev => {
|
, storeListener("stop", async ev => {
|
||||||
|
|
||||||
logger.info("Stopped receiver app", ev.detail);
|
logger.info("Stopping receiver app...", ev.detail);
|
||||||
|
|
||||||
await StatusManager.init();
|
receiverDevices.stopReceiverApp(ev.detail.receiver.id);
|
||||||
await StatusManager.stopReceiverApp(ev.detail.receiver);
|
|
||||||
|
|
||||||
resolve({
|
resolve({
|
||||||
actionType: ReceiverSelectionActionType.Stop
|
actionType: ReceiverSelectionActionType.Stop
|
||||||
@@ -205,10 +210,10 @@ async function getSelection(
|
|||||||
|
|
||||||
|
|
||||||
// Ensure status manager is initialized
|
// Ensure status manager is initialized
|
||||||
await StatusManager.init();
|
await receiverDevices.init();
|
||||||
|
|
||||||
sharedSelector.open(
|
sharedSelector.open(
|
||||||
Array.from(StatusManager.getReceivers())
|
receiverDevices.getDevices()
|
||||||
, defaultMediaType
|
, defaultMediaType
|
||||||
, availableMediaTypes
|
, availableMediaTypes
|
||||||
, currentShim?.appId);
|
, currentShim?.appId);
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import { Message, Port } from "../messaging";
|
|||||||
import nativeMessaging from "./nativeMessaging";
|
import nativeMessaging from "./nativeMessaging";
|
||||||
import options from "./options";
|
import options from "./options";
|
||||||
|
|
||||||
import { Receiver } from "../types";
|
import { ReceiverDevice } from "../types";
|
||||||
import { ReceiverSelectionCast
|
import { ReceiverSelectionCast
|
||||||
, ReceiverSelectionStop } from "../background/receiverSelector/ReceiverSelector";
|
, ReceiverSelectionStop } from "../background/receiverSelector/ReceiverSelector";
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,14 @@ export class Logger {
|
|||||||
console.info(formattedMessage);
|
console.info(formattedMessage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public warn(message: string, data?: any) {
|
||||||
|
const formattedMessage = `${this.prefix} (Warning): ${message}`;
|
||||||
|
if (data) {
|
||||||
|
console.warn(formattedMessage, data);
|
||||||
|
} else {
|
||||||
|
console.warn(formattedMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
public error(message: string, data?: any) {
|
public error(message: string, data?: any) {
|
||||||
const formattedMessage = `${this.prefix} (Error): ${message}`;
|
const formattedMessage = `${this.prefix} (Error): ${message}`;
|
||||||
if (data) {
|
if (data) {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import Messenger from "./lib/Messenger";
|
|||||||
import { TypedPort } from "./lib/TypedPort";
|
import { TypedPort } from "./lib/TypedPort";
|
||||||
|
|
||||||
import { BridgeInfo } from "./lib/bridge";
|
import { BridgeInfo } from "./lib/bridge";
|
||||||
import { Receiver, ReceiverStatus } from "./types";
|
import { ReceiverDevice, ReceiverStatus } from "./types";
|
||||||
import { ReceiverSelectorMediaType } from "./background/receiverSelector";
|
import { ReceiverSelectorMediaType } from "./background/receiverSelector";
|
||||||
import { ReceiverSelection, ReceiverSelectionCast, ReceiverSelectionStop }
|
import { ReceiverSelection, ReceiverSelectionCast, ReceiverSelectionStop }
|
||||||
from "./background/receiverSelector/ReceiverSelector";
|
from "./background/receiverSelector/ReceiverSelector";
|
||||||
@@ -34,7 +34,7 @@ import { MediaInfo } from "./shim/cast/media";
|
|||||||
type ExtMessageDefinitions = {
|
type ExtMessageDefinitions = {
|
||||||
"popup:init": { appId?: string }
|
"popup:init": { appId?: string }
|
||||||
, "popup:update": {
|
, "popup:update": {
|
||||||
receivers: Receiver[]
|
receivers: ReceiverDevice[]
|
||||||
, defaultMediaType?: ReceiverSelectorMediaType
|
, defaultMediaType?: ReceiverSelectorMediaType
|
||||||
, availableMediaTypes?: ReceiverSelectorMediaType
|
, availableMediaTypes?: ReceiverSelectorMediaType
|
||||||
}
|
}
|
||||||
@@ -53,10 +53,10 @@ type ExtMessageDefinitions = {
|
|||||||
, "main:sessionCreated": {}
|
, "main:sessionCreated": {}
|
||||||
|
|
||||||
, "shim:initialized": BridgeInfo
|
, "shim:initialized": BridgeInfo
|
||||||
, "shim:serviceUp": { id: Receiver["id"] }
|
, "shim:serviceUp": { id: ReceiverDevice["id"] }
|
||||||
, "shim:serviceDown": { id: Receiver["id"] }
|
, "shim:serviceDown": { id: ReceiverDevice["id"] }
|
||||||
|
|
||||||
, "shim:launchApp": { receiver: Receiver }
|
, "shim:launchApp": { receiver: ReceiverDevice }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -184,7 +184,7 @@ type AppMessageDefinitions = {
|
|||||||
, "bridge:openReceiverSelector": string
|
, "bridge:openReceiverSelector": string
|
||||||
, "bridge:closeReceiverSelector": {}
|
, "bridge:closeReceiverSelector": {}
|
||||||
|
|
||||||
, "bridge:stopReceiverApp": { receiver: Receiver }
|
, "bridge:stopReceiverApp": { receiverDevice: ReceiverDevice }
|
||||||
|
|
||||||
|
|
||||||
, "bridge:startMediaServer": {
|
, "bridge:startMediaServer": {
|
||||||
@@ -202,11 +202,10 @@ type AppMessageDefinitions = {
|
|||||||
, "mediaCast:mediaServerError": {}
|
, "mediaCast:mediaServerError": {}
|
||||||
|
|
||||||
|
|
||||||
, "main:serviceUp": Receiver
|
, "main:receiverDeviceUp": { receiverDevice: ReceiverDevice }
|
||||||
, "main:serviceDown": { id: string }
|
, "main:receiverDeviceDown": { receiverDeviceId: string }
|
||||||
|
, "main:receiverDeviceUpdated": {
|
||||||
, "main:updateReceiverStatus": {
|
receiverDeviceId: string
|
||||||
id: string
|
|
||||||
, status: ReceiverStatus
|
, status: ReceiverStatus
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import options from "../../lib/options";
|
|||||||
import cast, { ensureInit } from "../../shim/export";
|
import cast, { ensureInit } from "../../shim/export";
|
||||||
|
|
||||||
import { Message } from "../../messaging";
|
import { Message } from "../../messaging";
|
||||||
import { Receiver } from "../../types";
|
import { ReceiverDevice } from "../../types";
|
||||||
|
|
||||||
|
|
||||||
function startMediaServer(filePath: string, port: number)
|
function startMediaServer(filePath: string, port: number)
|
||||||
@@ -343,7 +343,7 @@ async function registerMediaElementListeners() {
|
|||||||
|
|
||||||
interface InitOptions {
|
interface InitOptions {
|
||||||
mediaUrl: string;
|
mediaUrl: string;
|
||||||
receiver: Receiver;
|
receiver: ReceiverDevice;
|
||||||
targetElementId?: number;
|
targetElementId?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,14 +4,14 @@ import options from "../lib/options";
|
|||||||
import cast, { ensureInit } from "../shim/export";
|
import cast, { ensureInit } from "../shim/export";
|
||||||
|
|
||||||
import { ReceiverSelectorMediaType } from "../background/receiverSelector";
|
import { ReceiverSelectorMediaType } from "../background/receiverSelector";
|
||||||
import { Receiver } from "../types";
|
import { ReceiverDevice } from "../types";
|
||||||
|
|
||||||
|
|
||||||
// Variables passed from background
|
// Variables passed from background
|
||||||
const { selectedMedia
|
const { selectedMedia
|
||||||
, selectedReceiver }
|
, selectedReceiver }
|
||||||
: { selectedMedia: ReceiverSelectorMediaType
|
: { selectedMedia: ReceiverSelectorMediaType
|
||||||
, selectedReceiver: Receiver } = (window as any);
|
, selectedReceiver: ReceiverDevice } = (window as any);
|
||||||
|
|
||||||
|
|
||||||
const FX_CAST_RECEIVER_APP_NAMESPACE = "urn:x-cast:fx_cast";
|
const FX_CAST_RECEIVER_APP_NAMESPACE = "urn:x-cast:fx_cast";
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import logger from "../../lib/logger";
|
import logger from "../../lib/logger";
|
||||||
|
|
||||||
import { Receiver } from "../../types";
|
import { ReceiverDevice } from "../../types";
|
||||||
import { onMessage, sendMessageResponse } from "../eventMessageChannel";
|
import { onMessage, sendMessageResponse } from "../eventMessageChannel";
|
||||||
|
|
||||||
import Session from "./Session";
|
import Session from "./Session";
|
||||||
@@ -177,7 +177,7 @@ export function requestSession(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function _requestSession(
|
export function _requestSession(
|
||||||
_receiver: Receiver
|
_receiver: ReceiverDevice
|
||||||
, successCallback?: RequestSessionSuccessCallback
|
, successCallback?: RequestSessionSuccessCallback
|
||||||
, errorCallback?: ErrorCallback): void {
|
, errorCallback?: ErrorCallback): void {
|
||||||
|
|
||||||
@@ -414,7 +414,7 @@ onMessage(async message => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case "shim:launchApp": {
|
case "shim:launchApp": {
|
||||||
const receiver: Receiver = message.data.receiver;
|
const receiver: ReceiverDevice = message.data.receiver;
|
||||||
_requestSession(receiver
|
_requestSession(receiver
|
||||||
, session => {
|
, session => {
|
||||||
apiConfig.sessionListener(session);
|
apiConfig.sessionListener(session);
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
import { Volume } from "./shim/cast/dataClasses";
|
import { Volume } from "./shim/cast/dataClasses";
|
||||||
|
|
||||||
|
|
||||||
export interface Receiver {
|
export interface ReceiverDevice {
|
||||||
host: string
|
host: string
|
||||||
friendlyName: string
|
friendlyName: string
|
||||||
, id: string
|
, id: string
|
||||||
@@ -25,8 +25,8 @@ export interface ReceiverStatus {
|
|||||||
, transportId: string
|
, transportId: string
|
||||||
, universalAppId: string
|
, universalAppId: string
|
||||||
}>
|
}>
|
||||||
, isActiveInput: boolean
|
, isActiveInput?: boolean
|
||||||
, isStandBy: boolean
|
, isStandBy?: boolean
|
||||||
, userEq: unknown
|
, userEq: unknown
|
||||||
, volume: Volume
|
, volume: Volume
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import options from "../../lib/options";
|
|||||||
|
|
||||||
import messaging, { Message, Port } from "../../messaging";
|
import messaging, { Message, Port } from "../../messaging";
|
||||||
import { getNextEllipsis } from "../../lib/utils";
|
import { getNextEllipsis } from "../../lib/utils";
|
||||||
import { Receiver } from "../../types";
|
import { ReceiverDevice } from "../../types";
|
||||||
|
|
||||||
import { ReceiverSelectionActionType
|
import { ReceiverSelectionActionType
|
||||||
, ReceiverSelectorMediaType } from "../../background/receiverSelector";
|
, ReceiverSelectorMediaType } from "../../background/receiverSelector";
|
||||||
@@ -31,7 +31,7 @@ browser.runtime.getPlatformInfo()
|
|||||||
|
|
||||||
interface PopupAppProps {}
|
interface PopupAppProps {}
|
||||||
interface PopupAppState {
|
interface PopupAppState {
|
||||||
receivers: Receiver[];
|
receivers: ReceiverDevice[];
|
||||||
mediaType: ReceiverSelectorMediaType;
|
mediaType: ReceiverSelectorMediaType;
|
||||||
availableMediaTypes: ReceiverSelectorMediaType;
|
availableMediaTypes: ReceiverSelectorMediaType;
|
||||||
isLoading: boolean;
|
isLoading: boolean;
|
||||||
@@ -92,7 +92,7 @@ class PopupApp extends Component<PopupAppProps, PopupAppState> {
|
|||||||
|
|
||||||
if (availableMediaTypes && defaultMediaType) {
|
if (availableMediaTypes && defaultMediaType) {
|
||||||
this.setState({
|
this.setState({
|
||||||
availableMediaTypes: availableMediaTypes
|
availableMediaTypes
|
||||||
, mediaType: defaultMediaType
|
, mediaType: defaultMediaType
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -214,7 +214,7 @@ class PopupApp extends Component<PopupAppProps, PopupAppState> {
|
|||||||
</>;
|
</>;
|
||||||
}
|
}
|
||||||
|
|
||||||
private onCast(receiver: Receiver) {
|
private onCast(receiver: ReceiverDevice) {
|
||||||
this.setState({
|
this.setState({
|
||||||
isLoading: true
|
isLoading: true
|
||||||
});
|
});
|
||||||
@@ -230,7 +230,7 @@ class PopupApp extends Component<PopupAppProps, PopupAppState> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private onStop(receiver: Receiver) {
|
private onStop(receiver: ReceiverDevice) {
|
||||||
this.port?.postMessage({
|
this.port?.postMessage({
|
||||||
subject: "receiverSelector:stop"
|
subject: "receiverSelector:stop"
|
||||||
, data: {
|
, data: {
|
||||||
@@ -274,11 +274,11 @@ class PopupApp extends Component<PopupAppProps, PopupAppState> {
|
|||||||
|
|
||||||
|
|
||||||
interface ReceiverEntryProps {
|
interface ReceiverEntryProps {
|
||||||
receiver: Receiver;
|
receiver: ReceiverDevice;
|
||||||
isLoading: boolean;
|
isLoading: boolean;
|
||||||
canCast: boolean;
|
canCast: boolean;
|
||||||
onCast (receiver: Receiver): void;
|
onCast (receiver: ReceiverDevice): void;
|
||||||
onStop (receiver: Receiver): void;
|
onStop (receiver: ReceiverDevice): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ReceiverEntryState {
|
interface ReceiverEntryState {
|
||||||
@@ -320,28 +320,27 @@ class ReceiverEntry extends Component<ReceiverEntryProps, ReceiverEntryState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
if (!this.props.receiver.status) {
|
const { status } = this.props.receiver;
|
||||||
|
if (!status) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { application } = this.props.receiver.status;
|
const application = status.applications?.[0];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<li className="receiver">
|
<li className="receiver">
|
||||||
<div className="receiver__name">
|
<div className="receiver__name">
|
||||||
{ this.props.receiver.friendlyName }
|
{ this.props.receiver.friendlyName }
|
||||||
</div>
|
</div>
|
||||||
<div className="receiver__address"
|
<div className="receiver__address">
|
||||||
title={ !application.isIdleScreen ? application.statusText : "" }>
|
{ application && !application.isIdleScreen
|
||||||
{ application.isIdleScreen
|
? application.statusText
|
||||||
? `${this.props.receiver.host}:${this.props.receiver.port}`
|
: `${this.props.receiver.host}:${this.props.receiver.port}` }
|
||||||
: application.statusText }
|
|
||||||
</div>
|
</div>
|
||||||
<button className="button receiver__connect"
|
<button className="button receiver__connect"
|
||||||
onClick={ this.handleCast }
|
onClick={ this.handleCast }
|
||||||
disabled={ this.state.showAlternateAction
|
disabled={ (application && application.isIdleScreen)
|
||||||
? application.isIdleScreen
|
?? (this.props.isLoading || !this.props.canCast) }>
|
||||||
: (this.props.isLoading || !this.props.canCast) }>
|
|
||||||
{ this.state.isLoading
|
{ this.state.isLoading
|
||||||
? _("popupCastingButtonTitle"
|
? _("popupCastingButtonTitle"
|
||||||
, (this.state.isLoading
|
, (this.state.isLoading
|
||||||
@@ -356,13 +355,14 @@ class ReceiverEntry extends Component<ReceiverEntryProps, ReceiverEntryState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private handleCast() {
|
private handleCast() {
|
||||||
if (!this.props.receiver.status) {
|
const { status } = this.props.receiver;
|
||||||
|
if (!status) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { application } = this.props.receiver.status;
|
const application = status.applications?.[0];
|
||||||
|
|
||||||
if (!application.isIdleScreen && this.state.showAlternateAction) {
|
if (!application?.isIdleScreen && this.state.showAlternateAction) {
|
||||||
this.props.onStop(this.props.receiver);
|
this.props.onStop(this.props.receiver);
|
||||||
} else {
|
} else {
|
||||||
this.props.onCast(this.props.receiver);
|
this.props.onCast(this.props.receiver);
|
||||||
|
|||||||
Reference in New Issue
Block a user