mirror of
https://github.com/hensm/fx_cast.git
synced 2026-06-12 18:39:58 +00:00
Narrow linting rules and fix for eslintrc for js files
This commit is contained in:
@@ -2,29 +2,47 @@
|
|||||||
"root": true,
|
"root": true,
|
||||||
"parser": "@typescript-eslint/parser",
|
"parser": "@typescript-eslint/parser",
|
||||||
"plugins": ["@typescript-eslint"],
|
"plugins": ["@typescript-eslint"],
|
||||||
"extends": [
|
"extends": ["eslint:recommended", "prettier"],
|
||||||
"eslint:recommended",
|
|
||||||
"plugin:@typescript-eslint/recommended",
|
|
||||||
"prettier"
|
|
||||||
],
|
|
||||||
"rules": {
|
"rules": {
|
||||||
"no-useless-escape": "off",
|
"no-useless-escape": "off",
|
||||||
"no-prototype-builtins": "off",
|
"no-prototype-builtins": "off",
|
||||||
"no-async-promise-executor": "off",
|
"no-async-promise-executor": "off",
|
||||||
"semi": ["error", "always"],
|
"semi": ["error", "always"],
|
||||||
"no-multiple-empty-lines": ["error", { "max": 2 }],
|
"no-multiple-empty-lines": ["error", { "max": 2 }],
|
||||||
"no-console": [ "error", {
|
"no-console": [
|
||||||
|
"error",
|
||||||
|
{
|
||||||
"allow": ["info", "warn", "error"]
|
"allow": ["info", "warn", "error"]
|
||||||
}],
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
"overrides": [
|
||||||
|
{
|
||||||
|
"files": ["*/bin/**/*.js"],
|
||||||
|
"env": {
|
||||||
|
"node": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"files": ["**/*.ts", "**/*.tsx"],
|
||||||
|
"extends": "plugin:@typescript-eslint/recommended",
|
||||||
|
"rules": {
|
||||||
"@typescript-eslint/no-empty-interface": "off",
|
"@typescript-eslint/no-empty-interface": "off",
|
||||||
"@typescript-eslint/no-explicit-any": "off",
|
"@typescript-eslint/no-explicit-any": "off",
|
||||||
"@typescript-eslint/explicit-module-boundary-types": "off",
|
"@typescript-eslint/explicit-module-boundary-types": "off",
|
||||||
"@typescript-eslint/no-unused-vars": "off",
|
"@typescript-eslint/no-unused-vars": [
|
||||||
"@typescript-eslint/ban-types": "off",
|
"error",
|
||||||
|
{ "argsIgnorePattern": "^_" }
|
||||||
|
],
|
||||||
"@typescript-eslint/ban-ts-comment": "off",
|
"@typescript-eslint/ban-ts-comment": "off",
|
||||||
"@typescript-eslint/no-this-alias": [ "error", {
|
"@typescript-eslint/no-this-alias": [
|
||||||
|
"error",
|
||||||
|
{
|
||||||
"allowedNames": ["this_"]
|
"allowedNames": ["this_"]
|
||||||
}]
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|||||||
@@ -489,8 +489,7 @@ function packageLinuxRpm(
|
|||||||
function packageWin32(
|
function packageWin32(
|
||||||
arch,
|
arch,
|
||||||
platformExecutableName,
|
platformExecutableName,
|
||||||
platformExecutablePath,
|
platformExecutablePath
|
||||||
platformManifestPath
|
|
||||||
) {
|
) {
|
||||||
const outputName = `${meta.__applicationName}-${meta.__applicationVersion}-${arch}.exe`;
|
const outputName = `${meta.__applicationName}-${meta.__applicationVersion}-${arch}.exe`;
|
||||||
|
|
||||||
@@ -525,6 +524,6 @@ function packageWin32(
|
|||||||
}
|
}
|
||||||
|
|
||||||
build().catch(e => {
|
build().catch(e => {
|
||||||
console.log("Build failed", e);
|
console.error("Build failed", e);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
});
|
});
|
||||||
|
|||||||
1
app/package-lock.json
generated
1
app/package-lock.json
generated
@@ -13,7 +13,6 @@
|
|||||||
"mime-types": "^2.1.35",
|
"mime-types": "^2.1.35",
|
||||||
"minimist": "^1.2.6",
|
"minimist": "^1.2.6",
|
||||||
"node-fetch": "^3.2.3",
|
"node-fetch": "^3.2.3",
|
||||||
"rage-edit": "*",
|
|
||||||
"tweetnacl": "^1.0.3",
|
"tweetnacl": "^1.0.3",
|
||||||
"ws": "^8.5.0"
|
"ws": "^8.5.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -72,8 +72,6 @@ export default class Session extends CastClient {
|
|||||||
this.establishAppConnection(this.transportId);
|
this.establishAppConnection(this.transportId);
|
||||||
this.onSessionCreated?.(this.sessionId);
|
this.onSessionCreated?.(this.sessionId);
|
||||||
|
|
||||||
const { friendlyName } = this.receiverDevice;
|
|
||||||
|
|
||||||
messaging.sendMessage({
|
messaging.sendMessage({
|
||||||
subject: "cast:sessionCreated",
|
subject: "cast:sessionCreated",
|
||||||
data: {
|
data: {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
import messaging, { Message } from "../../messaging";
|
import messaging, { Message } from "../../messaging";
|
||||||
|
|
||||||
import Session from "./Session";
|
import Session from "./Session";
|
||||||
import CastClient, { NS_CONNECTION, NS_RECEIVER } from "./client";
|
import CastClient from "./client";
|
||||||
|
|
||||||
const sessions = new Map<string, Session>();
|
const sessions = new Map<string, Session>();
|
||||||
|
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ interface BreakClip {
|
|||||||
contentId?: string;
|
contentId?: string;
|
||||||
contentType?: string;
|
contentType?: string;
|
||||||
contentUrl?: string;
|
contentUrl?: string;
|
||||||
customData?: {};
|
customData?: unknown;
|
||||||
duration?: number;
|
duration?: number;
|
||||||
id: string;
|
id: string;
|
||||||
hlsSegmentFormat?: HlsSegmentFormat;
|
hlsSegmentFormat?: HlsSegmentFormat;
|
||||||
@@ -137,7 +137,7 @@ interface BreakClip {
|
|||||||
|
|
||||||
interface TextTrackStyle {
|
interface TextTrackStyle {
|
||||||
backgroundColor: Nullable<string>;
|
backgroundColor: Nullable<string>;
|
||||||
customData: any;
|
customData: unknown;
|
||||||
edgeColor: Nullable<string>;
|
edgeColor: Nullable<string>;
|
||||||
edgeType: Nullable<string>;
|
edgeType: Nullable<string>;
|
||||||
fontFamily: Nullable<string>;
|
fontFamily: Nullable<string>;
|
||||||
@@ -151,7 +151,7 @@ interface TextTrackStyle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface Track {
|
interface Track {
|
||||||
customData: any;
|
customData: unknown;
|
||||||
language: Nullable<string>;
|
language: Nullable<string>;
|
||||||
name: Nullable<string>;
|
name: Nullable<string>;
|
||||||
subtype: Nullable<string>;
|
subtype: Nullable<string>;
|
||||||
@@ -162,7 +162,7 @@ interface Track {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface UserActionState {
|
interface UserActionState {
|
||||||
customData: any;
|
customData: unknown;
|
||||||
userAction: UserAction;
|
userAction: UserAction;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,7 +185,7 @@ interface MediaInformation {
|
|||||||
contentId: string;
|
contentId: string;
|
||||||
contentType: string;
|
contentType: string;
|
||||||
contentUrl?: string;
|
contentUrl?: string;
|
||||||
customData: any;
|
customData: unknown;
|
||||||
duration: Nullable<number>;
|
duration: Nullable<number>;
|
||||||
entity?: string;
|
entity?: string;
|
||||||
hlsSegmentFormat?: HlsSegmentFormat;
|
hlsSegmentFormat?: HlsSegmentFormat;
|
||||||
@@ -269,7 +269,7 @@ interface PhotoMediaMetadata {
|
|||||||
interface QueueItem {
|
interface QueueItem {
|
||||||
activeTrackIds: Nullable<number[]>;
|
activeTrackIds: Nullable<number[]>;
|
||||||
autoplay: boolean;
|
autoplay: boolean;
|
||||||
customData: any;
|
customData: unknown;
|
||||||
itemId: Nullable<number>;
|
itemId: Nullable<number>;
|
||||||
media: MediaInformation;
|
media: MediaInformation;
|
||||||
playbackDuration: Nullable<number>;
|
playbackDuration: Nullable<number>;
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { handleCastMessage } from "./components/cast";
|
|||||||
import { startDiscovery, stopDiscovery } from "./components/discovery";
|
import { startDiscovery, stopDiscovery } from "./components/discovery";
|
||||||
import { startMediaServer, stopMediaServer } from "./components/mediaServer";
|
import { startMediaServer, stopMediaServer } from "./components/mediaServer";
|
||||||
|
|
||||||
import { __applicationName, __applicationVersion } from "../../package.json";
|
import { __applicationVersion } from "../../package.json";
|
||||||
|
|
||||||
process.on("SIGTERM", () => {
|
process.on("SIGTERM", () => {
|
||||||
stopDiscovery();
|
stopDiscovery();
|
||||||
|
|||||||
@@ -37,7 +37,6 @@ export async function convertSrtToVtt(srtFilePath: string) {
|
|||||||
* millisecond separator.
|
* millisecond separator.
|
||||||
*/
|
*/
|
||||||
for (const groups of fileContents.matchAll(REGEX_CAPTION)) {
|
for (const groups of fileContents.matchAll(REGEX_CAPTION)) {
|
||||||
const captionSource = groups[0];
|
|
||||||
const captionIndex = groups[1];
|
const captionIndex = groups[1];
|
||||||
const captionTime = groups[2];
|
const captionTime = groups[2];
|
||||||
const captionText = groups[3];
|
const captionText = groups[3];
|
||||||
|
|||||||
@@ -163,12 +163,12 @@ type MessageDefinitions = {
|
|||||||
/**
|
/**
|
||||||
* Sent to bridge to stop HTTP media server.
|
* Sent to bridge to stop HTTP media server.
|
||||||
*/
|
*/
|
||||||
"bridge:stopMediaServer": {};
|
"bridge:stopMediaServer": undefined;
|
||||||
/**
|
/**
|
||||||
* Sent to media sender from bridge when the media server has
|
* Sent to media sender from bridge when the media server has
|
||||||
* stopped.
|
* stopped.
|
||||||
*/
|
*/
|
||||||
"mediaCast:mediaServerStopped": {};
|
"mediaCast:mediaServerStopped": undefined;
|
||||||
/**
|
/**
|
||||||
* Sent to media sender from bridge when the media server has
|
* Sent to media sender from bridge when the media server has
|
||||||
* encountered an error.
|
* encountered an error.
|
||||||
@@ -190,8 +190,8 @@ type Messages = {
|
|||||||
* all-optional keys.
|
* all-optional keys.
|
||||||
*/
|
*/
|
||||||
type NarrowedMessage<L extends MessageBase<keyof MessageDefinitions>> =
|
type NarrowedMessage<L extends MessageBase<keyof MessageDefinitions>> =
|
||||||
L extends any
|
L extends unknown
|
||||||
? {} extends L["data"]
|
? undefined extends L["data"]
|
||||||
? Omit<L, "data"> & Partial<L>
|
? Omit<L, "data"> & Partial<L>
|
||||||
: L
|
: L
|
||||||
: never;
|
: never;
|
||||||
@@ -231,7 +231,7 @@ class Messenger extends TypedEmitter<MessengerEvents> {
|
|||||||
this.encodeTransform.write(message);
|
this.encodeTransform.write(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
send(data: any) {
|
send(data: unknown) {
|
||||||
this.encodeTransform.write(data);
|
this.encodeTransform.write(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
import { Transform } from "stream";
|
import { Transform, TransformCallback } from "stream";
|
||||||
import { Message } from "./bridge/messaging";
|
import { Message } from "./bridge/messaging";
|
||||||
|
|
||||||
type ResponseHandlerFunction = (message: Message) => Promise<any>;
|
type ResponseHandlerFunction = (message: Message) => Promise<unknown>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Takes a handler function that implements the transform
|
* Takes a handler function that implements the transform
|
||||||
@@ -20,8 +20,7 @@ export class ResponseTransform extends Transform {
|
|||||||
public _transform(
|
public _transform(
|
||||||
chunk: Message,
|
chunk: Message,
|
||||||
_encoding: string,
|
_encoding: string,
|
||||||
// tslint:disable-next-line:ban-types
|
callback: TransformCallback
|
||||||
callback: Function
|
|
||||||
) {
|
) {
|
||||||
Promise.resolve(this._handler(chunk)).then(res => {
|
Promise.resolve(this._handler(chunk)).then(res => {
|
||||||
if (res) {
|
if (res) {
|
||||||
@@ -49,10 +48,10 @@ export class DecodeTransform extends Transform {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public _transform(
|
public _transform(
|
||||||
chunk: any,
|
chunk: Uint8Array,
|
||||||
_encoding: string,
|
_encoding: string,
|
||||||
// tslint:disable-next-line:ban-types
|
// tslint:disable-next-line:ban-types
|
||||||
callback: Function
|
callback: TransformCallback
|
||||||
) {
|
) {
|
||||||
// Append next chunk to buffer
|
// Append next chunk to buffer
|
||||||
this._messageBuffer = Buffer.concat([this._messageBuffer, chunk]);
|
this._messageBuffer = Buffer.concat([this._messageBuffer, chunk]);
|
||||||
@@ -108,10 +107,10 @@ export class EncodeTransform extends Transform {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public _transform(
|
public _transform(
|
||||||
chunk: any,
|
chunk: Uint8Array,
|
||||||
_encoding: string,
|
_encoding: string,
|
||||||
// tslint:disable-next-line:ban-types
|
// tslint:disable-next-line:ban-types
|
||||||
callback: Function
|
callback: TransformCallback
|
||||||
) {
|
) {
|
||||||
const messageLength = Buffer.alloc(4);
|
const messageLength = Buffer.alloc(4);
|
||||||
const message = Buffer.from(JSON.stringify(chunk));
|
const message = Buffer.from(JSON.stringify(chunk));
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ const preactCompatPlugin = {
|
|||||||
"../node_modules/preact/compat/dist/compat.module.js"
|
"../node_modules/preact/compat/dist/compat.module.js"
|
||||||
);
|
);
|
||||||
|
|
||||||
build.onResolve({ filter: /^(react|react-dom)$/ }, args => ({
|
build.onResolve({ filter: /^(react|react-dom)$/ }, () => ({
|
||||||
path: preactPath
|
path: preactPath
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import logger from "../lib/logger";
|
|||||||
import { TypedEventTarget } from "../lib/TypedEventTarget";
|
import { TypedEventTarget } from "../lib/TypedEventTarget";
|
||||||
|
|
||||||
import { Message, Port } from "../messaging";
|
import { Message, Port } from "../messaging";
|
||||||
import { ReceiverDevice, ReceiverDeviceCapabilities } from "../types";
|
import { ReceiverDevice } from "../types";
|
||||||
import { ReceiverStatus } from "../cast/sdk/types";
|
import { ReceiverStatus } from "../cast/sdk/types";
|
||||||
|
|
||||||
interface EventMap {
|
interface EventMap {
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
import logger from "../lib/logger";
|
import logger from "../lib/logger";
|
||||||
import { TypedEventTarget } from "../lib/TypedEventTarget";
|
|
||||||
import { Message } from "../messaging";
|
import { Message } from "../messaging";
|
||||||
|
|
||||||
type EventMessengerListener = (message: Message) => void;
|
type EventMessengerListener = (message: Message) => void;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
import messaging, { Message } from "../messaging";
|
import { Message } from "../messaging";
|
||||||
|
|
||||||
import { BridgeInfo } from "../lib/bridge";
|
import { BridgeInfo } from "../lib/bridge";
|
||||||
import { TypedMessagePort } from "../lib/TypedMessagePort";
|
import { TypedMessagePort } from "../lib/TypedMessagePort";
|
||||||
|
|||||||
@@ -17,8 +17,7 @@ if (!_window.chrome) {
|
|||||||
// Create page-accessible API object
|
// Create page-accessible API object
|
||||||
_window.chrome.cast = new CastSDK();
|
_window.chrome.cast = new CastSDK();
|
||||||
|
|
||||||
let bridgeInfo: any;
|
let frameworkScriptPromise: Promise<HTMLScriptElement> | undefined;
|
||||||
let frameworkScriptPromise: Promise<HTMLScriptElement>;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If loaded within a page via a <script> element,
|
* If loaded within a page via a <script> element,
|
||||||
@@ -27,8 +26,9 @@ let frameworkScriptPromise: Promise<HTMLScriptElement>;
|
|||||||
*/
|
*/
|
||||||
if (document.currentScript) {
|
if (document.currentScript) {
|
||||||
const currentScript = document.currentScript as HTMLScriptElement;
|
const currentScript = document.currentScript as HTMLScriptElement;
|
||||||
const currentScriptUrl = new URL(currentScript.src);
|
const currentScriptParams = new URLSearchParams(
|
||||||
const currentScriptParams = new URLSearchParams(currentScriptUrl.search);
|
new URL(currentScript.src).search
|
||||||
|
);
|
||||||
|
|
||||||
// Load Framework API if requested
|
// Load Framework API if requested
|
||||||
if (currentScriptParams.get("loadCastFramework") === "1") {
|
if (currentScriptParams.get("loadCastFramework") === "1") {
|
||||||
@@ -43,17 +43,13 @@ if (document.currentScript) {
|
|||||||
eventMessaging.page.addListener(async message => {
|
eventMessaging.page.addListener(async message => {
|
||||||
switch (message.subject) {
|
switch (message.subject) {
|
||||||
case "cast:initialized": {
|
case "cast:initialized": {
|
||||||
bridgeInfo = message.data;
|
|
||||||
|
|
||||||
// If framework API is requested, ensure loaded
|
// If framework API is requested, ensure loaded
|
||||||
if (frameworkScriptPromise) {
|
|
||||||
await frameworkScriptPromise;
|
await frameworkScriptPromise;
|
||||||
}
|
|
||||||
|
|
||||||
// Call page script/framework API script's init function
|
// Call page script/framework API script's init function
|
||||||
const initFn = _window.__onGCastApiAvailable;
|
const initFn = _window.__onGCastApiAvailable;
|
||||||
if (initFn && typeof initFn === "function") {
|
if (initFn && typeof initFn === "function") {
|
||||||
initFn(bridgeInfo && bridgeInfo.isVersionCompatible);
|
initFn(message.data.isVersionCompatible);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ export class Error {
|
|||||||
constructor(
|
constructor(
|
||||||
public code: string,
|
public code: string,
|
||||||
public description: Nullable<string> = null,
|
public description: Nullable<string> = null,
|
||||||
public details: any = null
|
public details: unknown = null
|
||||||
) {}
|
) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ export default class Media {
|
|||||||
activeTrackIds: Nullable<number[]> = null;
|
activeTrackIds: Nullable<number[]> = null;
|
||||||
breakStatus?: BreakStatus;
|
breakStatus?: BreakStatus;
|
||||||
currentTime = 0;
|
currentTime = 0;
|
||||||
customData: any = null;
|
customData: unknown = null;
|
||||||
idleReason: Nullable<string> = null;
|
idleReason: Nullable<string> = null;
|
||||||
liveSeekableRange?: LiveSeekableRange;
|
liveSeekableRange?: LiveSeekableRange;
|
||||||
media: Nullable<MediaInfo> = null;
|
media: Nullable<MediaInfo> = null;
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ export class BreakClip {
|
|||||||
contentId?: string;
|
contentId?: string;
|
||||||
contentType?: string;
|
contentType?: string;
|
||||||
contentUrl?: string;
|
contentUrl?: string;
|
||||||
customData?: {};
|
customData?: unknown;
|
||||||
duration?: number;
|
duration?: number;
|
||||||
hlsSegmentFormat?: HlsSegmentFormat;
|
hlsSegmentFormat?: HlsSegmentFormat;
|
||||||
posterUrl?: string;
|
posterUrl?: string;
|
||||||
@@ -99,7 +99,7 @@ export class GenericMediaMetadata {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class GetStatusRequest {
|
export class GetStatusRequest {
|
||||||
customData: any = null;
|
customData: unknown = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class LiveSeekableRange {
|
export class LiveSeekableRange {
|
||||||
@@ -117,7 +117,7 @@ export class LoadRequest {
|
|||||||
atvCredentialsType?: string;
|
atvCredentialsType?: string;
|
||||||
autoplay: Nullable<boolean> = true;
|
autoplay: Nullable<boolean> = true;
|
||||||
currentTime: Nullable<number> = null;
|
currentTime: Nullable<number> = null;
|
||||||
customData: any = null;
|
customData: unknown = null;
|
||||||
media: MediaInfo;
|
media: MediaInfo;
|
||||||
requestId = 0;
|
requestId = 0;
|
||||||
sessionId: Nullable<string> = null;
|
sessionId: Nullable<string> = null;
|
||||||
@@ -139,7 +139,7 @@ export class MediaInfo {
|
|||||||
atvEntity?: string;
|
atvEntity?: string;
|
||||||
breakClips?: BreakClip[];
|
breakClips?: BreakClip[];
|
||||||
breaks?: Break[];
|
breaks?: Break[];
|
||||||
customData: any = null;
|
customData: unknown = null;
|
||||||
contentUrl?: string;
|
contentUrl?: string;
|
||||||
duration: Nullable<number> = null;
|
duration: Nullable<number> = null;
|
||||||
entity?: string;
|
entity?: string;
|
||||||
@@ -200,7 +200,7 @@ export class MusicTrackMediaMetadata {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class PauseRequest {
|
export class PauseRequest {
|
||||||
customData: any = null;
|
customData: unknown = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class PhotoMediaMetadata {
|
export class PhotoMediaMetadata {
|
||||||
@@ -218,7 +218,7 @@ export class PhotoMediaMetadata {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class PlayRequest {
|
export class PlayRequest {
|
||||||
customData: any = null;
|
customData: unknown = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class QueueData {
|
export class QueueData {
|
||||||
@@ -236,7 +236,7 @@ export class QueueData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class QueueInsertItemsRequest {
|
export class QueueInsertItemsRequest {
|
||||||
customData: any = null;
|
customData: unknown = null;
|
||||||
insertBefore: Nullable<number> = null;
|
insertBefore: Nullable<number> = null;
|
||||||
requestId: Nullable<number> = null;
|
requestId: Nullable<number> = null;
|
||||||
sessionId: Nullable<string> = null;
|
sessionId: Nullable<string> = null;
|
||||||
@@ -248,7 +248,7 @@ export class QueueInsertItemsRequest {
|
|||||||
export class QueueItem {
|
export class QueueItem {
|
||||||
activeTrackIds: Nullable<number[]> = null;
|
activeTrackIds: Nullable<number[]> = null;
|
||||||
autoplay = true;
|
autoplay = true;
|
||||||
customData: any = null;
|
customData: unknown = null;
|
||||||
itemId: Nullable<number> = null;
|
itemId: Nullable<number> = null;
|
||||||
media: MediaInfo;
|
media: MediaInfo;
|
||||||
playbackDuration: Nullable<number> = null;
|
playbackDuration: Nullable<number> = null;
|
||||||
@@ -268,7 +268,7 @@ export class QueueJumpRequest {
|
|||||||
|
|
||||||
export class QueueLoadRequest {
|
export class QueueLoadRequest {
|
||||||
type = "QUEUE_LOAD";
|
type = "QUEUE_LOAD";
|
||||||
customData: any = null;
|
customData: unknown = null;
|
||||||
repeatMode: string = RepeatMode.OFF;
|
repeatMode: string = RepeatMode.OFF;
|
||||||
startIndex = 0;
|
startIndex = 0;
|
||||||
|
|
||||||
@@ -277,13 +277,13 @@ export class QueueLoadRequest {
|
|||||||
|
|
||||||
export class QueueRemoveItemsRequest {
|
export class QueueRemoveItemsRequest {
|
||||||
type = "QUEUE_REMOVE";
|
type = "QUEUE_REMOVE";
|
||||||
customData: any = null;
|
customData: unknown = null;
|
||||||
|
|
||||||
constructor(public itemIds: number[]) {}
|
constructor(public itemIds: number[]) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class QueueReorderItemsRequest {
|
export class QueueReorderItemsRequest {
|
||||||
customData: any = null;
|
customData: unknown = null;
|
||||||
insertBefore: Nullable<number> = null;
|
insertBefore: Nullable<number> = null;
|
||||||
type = "QUEUE_REORDER";
|
type = "QUEUE_REORDER";
|
||||||
|
|
||||||
@@ -292,30 +292,30 @@ export class QueueReorderItemsRequest {
|
|||||||
|
|
||||||
export class QueueSetPropertiesRequest {
|
export class QueueSetPropertiesRequest {
|
||||||
type = "QUEUE_UPDATE";
|
type = "QUEUE_UPDATE";
|
||||||
customData: any = null;
|
customData: unknown = null;
|
||||||
repeatMode: Nullable<string> = null;
|
repeatMode: Nullable<string> = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class QueueUpdateItemsRequest {
|
export class QueueUpdateItemsRequest {
|
||||||
type = "QUEUE_UPDATE";
|
type = "QUEUE_UPDATE";
|
||||||
customData: any = null;
|
customData: unknown = null;
|
||||||
|
|
||||||
constructor(public items: QueueItem[]) {}
|
constructor(public items: QueueItem[]) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class SeekRequest {
|
export class SeekRequest {
|
||||||
currentTime: Nullable<number> = null;
|
currentTime: Nullable<number> = null;
|
||||||
customData: any = null;
|
customData: unknown = null;
|
||||||
resumeState: Nullable<ResumeState> = null;
|
resumeState: Nullable<ResumeState> = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class StopRequest {
|
export class StopRequest {
|
||||||
customData: any = null;
|
customData: unknown = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class TextTrackStyle {
|
export class TextTrackStyle {
|
||||||
backgroundColor: Nullable<string> = null;
|
backgroundColor: Nullable<string> = null;
|
||||||
customData: any = null;
|
customData: unknown = null;
|
||||||
edgeColor: Nullable<string> = null;
|
edgeColor: Nullable<string> = null;
|
||||||
edgeType: Nullable<string> = null;
|
edgeType: Nullable<string> = null;
|
||||||
fontFamily: Nullable<string> = null;
|
fontFamily: Nullable<string> = null;
|
||||||
@@ -329,7 +329,7 @@ export class TextTrackStyle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class Track {
|
export class Track {
|
||||||
customData: any = null;
|
customData: unknown = null;
|
||||||
language: Nullable<string> = null;
|
language: Nullable<string> = null;
|
||||||
name: Nullable<string> = null;
|
name: Nullable<string> = null;
|
||||||
subtype: Nullable<string> = null;
|
subtype: Nullable<string> = null;
|
||||||
@@ -355,7 +355,7 @@ export class TvShowMediaMetadata {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class UserActionState {
|
export class UserActionState {
|
||||||
customData: any = null;
|
customData: unknown = null;
|
||||||
|
|
||||||
constructor(public userAction: UserAction) {}
|
constructor(public userAction: UserAction) {}
|
||||||
}
|
}
|
||||||
@@ -374,7 +374,7 @@ export class VideoInformation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class VolumeRequest {
|
export class VolumeRequest {
|
||||||
customData: any = null;
|
customData: unknown = null;
|
||||||
|
|
||||||
constructor(public volume: Volume) {}
|
constructor(public volume: Volume) {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,10 @@ import cast, { ensureInit } from "../../export";
|
|||||||
import { Message } from "../../../messaging";
|
import { Message } from "../../../messaging";
|
||||||
import { ReceiverDevice } from "../../../types";
|
import { ReceiverDevice } from "../../../types";
|
||||||
|
|
||||||
|
import type Session from "../../sdk/Session";
|
||||||
|
import type Media from "../../sdk/media/Media";
|
||||||
|
import type { Error as Error_ } from "../../sdk/classes";
|
||||||
|
|
||||||
function startMediaServer(
|
function startMediaServer(
|
||||||
filePath: string,
|
filePath: string,
|
||||||
port: number
|
port: number
|
||||||
@@ -49,12 +53,12 @@ function startMediaServer(
|
|||||||
|
|
||||||
let backgroundPort: MessagePort;
|
let backgroundPort: MessagePort;
|
||||||
|
|
||||||
let currentSession: cast.Session;
|
let currentSession: Session;
|
||||||
let currentMedia: cast.media.Media;
|
let currentMedia: Media;
|
||||||
|
|
||||||
let targetElement: HTMLElement;
|
let targetElement: HTMLElement;
|
||||||
|
|
||||||
function getSession(opts: InitOptions): Promise<cast.Session> {
|
function getSession(opts: InitOptions): Promise<Session> {
|
||||||
return new Promise(async (resolve, reject) => {
|
return new Promise(async (resolve, reject) => {
|
||||||
/**
|
/**
|
||||||
* If a receiver is available, call requestSession. If a
|
* If a receiver is available, call requestSession. If a
|
||||||
@@ -76,10 +80,10 @@ function getSession(opts: InitOptions): Promise<cast.Session> {
|
|||||||
// TODO: Handle this
|
// TODO: Handle this
|
||||||
}
|
}
|
||||||
|
|
||||||
function onRequestSessionSuccess(session: cast.Session) {
|
function onRequestSessionSuccess(session: Session) {
|
||||||
resolve(session);
|
resolve(session);
|
||||||
}
|
}
|
||||||
function onRequestSessionError(err: cast.Error) {
|
function onRequestSessionError(err: Error_) {
|
||||||
reject(err.description);
|
reject(err.description);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,7 +101,7 @@ function getSession(opts: InitOptions): Promise<cast.Session> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function getMedia(opts: InitOptions): Promise<cast.media.Media> {
|
function getMedia(opts: InitOptions): Promise<Media> {
|
||||||
return new Promise(async (resolve, reject) => {
|
return new Promise(async (resolve, reject) => {
|
||||||
let mediaUrl = new URL(opts.mediaUrl);
|
let mediaUrl = new URL(opts.mediaUrl);
|
||||||
const mediaTitle = mediaUrl.pathname.slice(1);
|
const mediaTitle = mediaUrl.pathname.slice(1);
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ import cast, { ensureInit } from "../export";
|
|||||||
import { ReceiverSelectorMediaType } from "../../background/receiverSelector";
|
import { ReceiverSelectorMediaType } from "../../background/receiverSelector";
|
||||||
import { ReceiverDevice } from "../../types";
|
import { ReceiverDevice } from "../../types";
|
||||||
|
|
||||||
|
import type Session from "../sdk/Session";
|
||||||
|
|
||||||
// Variables passed from background
|
// Variables passed from background
|
||||||
const {
|
const {
|
||||||
selectedMedia,
|
selectedMedia,
|
||||||
@@ -17,7 +19,7 @@ const {
|
|||||||
|
|
||||||
const FX_CAST_RECEIVER_APP_NAMESPACE = "urn:x-cast:fx_cast";
|
const FX_CAST_RECEIVER_APP_NAMESPACE = "urn:x-cast:fx_cast";
|
||||||
|
|
||||||
let session: cast.Session;
|
let session: Session;
|
||||||
let wasSessionRequested = false;
|
let wasSessionRequested = false;
|
||||||
|
|
||||||
let peerConnection: RTCPeerConnection;
|
let peerConnection: RTCPeerConnection;
|
||||||
@@ -26,7 +28,7 @@ let peerConnection: RTCPeerConnection;
|
|||||||
* Sends a message to the fx_cast app running on the
|
* Sends a message to the fx_cast app running on the
|
||||||
* receiver device.
|
* receiver device.
|
||||||
*/
|
*/
|
||||||
function sendAppMessage(subject: string, data: any) {
|
function sendAppMessage(subject: string, data: unknown) {
|
||||||
if (!session) {
|
if (!session) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -41,7 +43,7 @@ window.addEventListener("beforeunload", () => {
|
|||||||
sendAppMessage("close", null);
|
sendAppMessage("close", null);
|
||||||
});
|
});
|
||||||
|
|
||||||
async function onRequestSessionSuccess(newSession: cast.Session) {
|
async function onRequestSessionSuccess(newSession: Session) {
|
||||||
cast.logMessage("onRequestSessionSuccess");
|
cast.logMessage("onRequestSessionSuccess");
|
||||||
|
|
||||||
session = newSession;
|
session = newSession;
|
||||||
|
|||||||
4
ext/src/global.d.ts
vendored
4
ext/src/global.d.ts
vendored
@@ -1,3 +1,5 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||||
|
|
||||||
declare const BRIDGE_VERSION: string;
|
declare const BRIDGE_VERSION: string;
|
||||||
declare const BRIDGE_NAME: string;
|
declare const BRIDGE_NAME: string;
|
||||||
declare const MIRRORING_APP_ID: string;
|
declare const MIRRORING_APP_ID: string;
|
||||||
@@ -68,7 +70,7 @@ type ExportFunctionFunc = (...args: any[]) => any;
|
|||||||
|
|
||||||
declare function exportFunction(
|
declare function exportFunction(
|
||||||
func: ExportFunctionFunc,
|
func: ExportFunctionFunc,
|
||||||
targetScope: any,
|
targetScope: Window,
|
||||||
options?: ExportFunctionOptions
|
options?: ExportFunctionOptions
|
||||||
): ExportFunctionFunc;
|
): ExportFunctionFunc;
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
export class Logger {
|
export class Logger {
|
||||||
constructor(private prefix: string) {}
|
constructor(private prefix: string) {}
|
||||||
|
|
||||||
public log(message: string, data?: any) {
|
public log(message: string, data?: unknown) {
|
||||||
const formattedMessage = `${this.prefix} (Log): ${message}`;
|
const formattedMessage = `${this.prefix} (Log): ${message}`;
|
||||||
if (data) {
|
if (data) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
@@ -13,7 +13,7 @@ export class Logger {
|
|||||||
console.log(formattedMessage);
|
console.log(formattedMessage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public info(message: string, data?: any) {
|
public info(message: string, data?: unknown) {
|
||||||
const formattedMessage = `${this.prefix} (Info): ${message}`;
|
const formattedMessage = `${this.prefix} (Info): ${message}`;
|
||||||
if (data) {
|
if (data) {
|
||||||
console.info(formattedMessage, data);
|
console.info(formattedMessage, data);
|
||||||
@@ -21,7 +21,7 @@ export class Logger {
|
|||||||
console.info(formattedMessage);
|
console.info(formattedMessage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public warn(message: string, data?: any) {
|
public warn(message: string, data?: unknown) {
|
||||||
const formattedMessage = `${this.prefix} (Warning): ${message}`;
|
const formattedMessage = `${this.prefix} (Warning): ${message}`;
|
||||||
if (data) {
|
if (data) {
|
||||||
console.warn(formattedMessage, data);
|
console.warn(formattedMessage, data);
|
||||||
@@ -29,7 +29,7 @@ export class Logger {
|
|||||||
console.warn(formattedMessage);
|
console.warn(formattedMessage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public error(message: string, data?: any) {
|
public error(message: string, data?: unknown) {
|
||||||
const formattedMessage = `${this.prefix} (Error): ${message}`;
|
const formattedMessage = `${this.prefix} (Error): ${message}`;
|
||||||
if (data) {
|
if (data) {
|
||||||
console.error(formattedMessage, data);
|
console.error(formattedMessage, data);
|
||||||
|
|||||||
@@ -32,7 +32,6 @@ function connectNative(application: string): Port {
|
|||||||
|
|
||||||
// Port proxy API
|
// Port proxy API
|
||||||
const portObject: Port = {
|
const portObject: Port = {
|
||||||
error: null as any,
|
|
||||||
name: "",
|
name: "",
|
||||||
|
|
||||||
onDisconnect: {
|
onDisconnect: {
|
||||||
@@ -150,7 +149,7 @@ function connectNative(application: string): Port {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
port.onMessage.addListener((message: any) => {
|
port.onMessage.addListener((message: Message) => {
|
||||||
if (!isNativeHostStatusKnown) {
|
if (!isNativeHostStatusKnown) {
|
||||||
isNativeHostStatusKnown = true;
|
isNativeHostStatusKnown = true;
|
||||||
messageQueue = [];
|
messageQueue = [];
|
||||||
@@ -177,8 +176,6 @@ async function sendNativeMessage(application: string, message: Message) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const port = await options.get("bridgeBackupPort");
|
|
||||||
|
|
||||||
return await new Promise((resolve, reject) => {
|
return await new Promise((resolve, reject) => {
|
||||||
const ws = new WebSocket(
|
const ws = new WebSocket(
|
||||||
`ws://${bridgeBackupHost}:${bridgeBackupPort}`
|
`ws://${bridgeBackupHost}:${bridgeBackupPort}`
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
import logger from "./logger";
|
|
||||||
|
|
||||||
import { ReceiverSelectorMediaType } from "../background/receiverSelector";
|
import { ReceiverSelectorMediaType } from "../background/receiverSelector";
|
||||||
|
|
||||||
export function getNextEllipsis(ellipsis: string): string {
|
export function getNextEllipsis(ellipsis: string): string {
|
||||||
@@ -18,7 +16,7 @@ export function getNextEllipsis(ellipsis: string): string {
|
|||||||
*/
|
*/
|
||||||
export function stringify(
|
export function stringify(
|
||||||
templateStrings: TemplateStringsArray,
|
templateStrings: TemplateStringsArray,
|
||||||
...substitutions: any[]
|
...substitutions: unknown[]
|
||||||
) {
|
) {
|
||||||
let formattedString = "";
|
let formattedString = "";
|
||||||
|
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ type ExtMessageDefinitions = {
|
|||||||
defaultMediaType?: ReceiverSelectorMediaType;
|
defaultMediaType?: ReceiverSelectorMediaType;
|
||||||
availableMediaTypes?: ReceiverSelectorMediaType;
|
availableMediaTypes?: ReceiverSelectorMediaType;
|
||||||
};
|
};
|
||||||
"popup:close": {};
|
"popup:close": undefined;
|
||||||
|
|
||||||
"receiverSelector:selected": ReceiverSelection;
|
"receiverSelector:selected": ReceiverSelection;
|
||||||
"receiverSelector:stop": ReceiverSelection;
|
"receiverSelector:stop": ReceiverSelection;
|
||||||
@@ -62,9 +62,9 @@ type ExtMessageDefinitions = {
|
|||||||
};
|
};
|
||||||
"cast:selectReceiver/selected": ReceiverSelectionCast;
|
"cast:selectReceiver/selected": ReceiverSelectionCast;
|
||||||
"cast:selectReceiver/stopped": ReceiverSelectionStop;
|
"cast:selectReceiver/stopped": ReceiverSelectionStop;
|
||||||
"cast:selectReceiver/cancelled": {};
|
"cast:selectReceiver/cancelled": undefined;
|
||||||
|
|
||||||
"main:closeReceiverSelector": {};
|
"main:closeReceiverSelector": undefined;
|
||||||
|
|
||||||
"main:initializeCast": { appId: string };
|
"main:initializeCast": { appId: string };
|
||||||
"cast:initialized": BridgeInfo;
|
"cast:initialized": BridgeInfo;
|
||||||
@@ -221,12 +221,12 @@ type AppMessageDefinitions = {
|
|||||||
/**
|
/**
|
||||||
* Sent to bridge to stop HTTP media server.
|
* Sent to bridge to stop HTTP media server.
|
||||||
*/
|
*/
|
||||||
"bridge:stopMediaServer": {};
|
"bridge:stopMediaServer": undefined;
|
||||||
/**
|
/**
|
||||||
* Sent to media sender from bridge when the media server has
|
* Sent to media sender from bridge when the media server has
|
||||||
* stopped.
|
* stopped.
|
||||||
*/
|
*/
|
||||||
"mediaCast:mediaServerStopped": {};
|
"mediaCast:mediaServerStopped": undefined;
|
||||||
/**
|
/**
|
||||||
* Sent to media sender from bridge when the media server has
|
* Sent to media sender from bridge when the media server has
|
||||||
* encountered an error.
|
* encountered an error.
|
||||||
@@ -250,8 +250,8 @@ type Messages = {
|
|||||||
* all-optional keys.
|
* all-optional keys.
|
||||||
*/
|
*/
|
||||||
type NarrowedMessage<L extends MessageBase<keyof MessageDefinitions>> =
|
type NarrowedMessage<L extends MessageBase<keyof MessageDefinitions>> =
|
||||||
L extends any
|
L extends unknown
|
||||||
? {} extends L["data"]
|
? undefined extends L["data"]
|
||||||
? Omit<L, "data"> & Partial<L>
|
? Omit<L, "data"> & Partial<L>
|
||||||
: L
|
: L
|
||||||
: never;
|
: never;
|
||||||
@@ -264,22 +264,28 @@ export type Message = NarrowedMessage<Messages[keyof Messages]>;
|
|||||||
*/
|
*/
|
||||||
export default new (class Messenger {
|
export default new (class Messenger {
|
||||||
connect(connectInfo: { name: string }) {
|
connect(connectInfo: { name: string }) {
|
||||||
return browser.runtime.connect(connectInfo) as unknown as Port;
|
return browser.runtime.connect(connectInfo) as Port;
|
||||||
}
|
}
|
||||||
|
|
||||||
connectTab(tabId: number, connectInfo: { name: string; frameId: number }) {
|
connectTab(tabId: number, connectInfo: { name: string; frameId: number }) {
|
||||||
return browser.tabs.connect(tabId, connectInfo) as unknown as Port;
|
return browser.tabs.connect(tabId, connectInfo) as Port;
|
||||||
}
|
}
|
||||||
|
|
||||||
onConnect = {
|
onConnect = {
|
||||||
addListener(cb: (port: Port) => void) {
|
addListener(cb: (port: Port) => void) {
|
||||||
browser.runtime.onConnect.addListener(cb as any);
|
browser.runtime.onConnect.addListener(
|
||||||
|
cb as (port: browser.runtime.Port) => void
|
||||||
|
);
|
||||||
},
|
},
|
||||||
removeListener(cb: (port: Port) => void) {
|
removeListener(cb: (port: Port) => void) {
|
||||||
browser.runtime.onConnect.removeListener(cb as any);
|
browser.runtime.onConnect.removeListener(
|
||||||
|
cb as (port: browser.runtime.Port) => void
|
||||||
|
);
|
||||||
},
|
},
|
||||||
hasListener(cb: (port: Port) => void) {
|
hasListener(cb: (port: Port) => void) {
|
||||||
return browser.runtime.onConnect.hasListener(cb as any);
|
return browser.runtime.onConnect.hasListener(
|
||||||
|
cb as (port: browser.runtime.Port) => void
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
|
|||||||
@@ -4,14 +4,23 @@
|
|||||||
import React, { Component } from "react";
|
import React, { Component } from "react";
|
||||||
import semver from "semver";
|
import semver from "semver";
|
||||||
|
|
||||||
import options, { Options } from "../../lib/options";
|
import { Options } from "../../lib/options";
|
||||||
|
|
||||||
import { BridgeInfo } from "../../lib/bridge";
|
import { BridgeInfo } from "../../lib/bridge";
|
||||||
import { getNextEllipsis } from "../../lib/utils";
|
import { getNextEllipsis } from "../../lib/utils";
|
||||||
|
import logger from "../../lib/logger";
|
||||||
|
|
||||||
const _ = browser.i18n.getMessage;
|
const _ = browser.i18n.getMessage;
|
||||||
|
|
||||||
|
interface Release {
|
||||||
|
url: string;
|
||||||
|
tag_name: string;
|
||||||
|
html_url: string;
|
||||||
|
assets: Array<{
|
||||||
|
content_type: string;
|
||||||
|
html_url: string;
|
||||||
|
}>;
|
||||||
|
}
|
||||||
|
|
||||||
interface BridgeStatsProps {
|
interface BridgeStatsProps {
|
||||||
info: BridgeInfo;
|
info: BridgeInfo;
|
||||||
@@ -44,21 +53,18 @@ const BridgeStats = (props: BridgeStatsProps) => (
|
|||||||
<tr>
|
<tr>
|
||||||
<th>{_("optionsBridgeStatsRecommendedAction")}</th>
|
<th>{_("optionsBridgeStatsRecommendedAction")}</th>
|
||||||
<td>
|
<td>
|
||||||
{
|
{props.info.isVersionCompatible
|
||||||
props.info.isVersionCompatible
|
|
||||||
? _("optionsBridgeNoAction")
|
? _("optionsBridgeNoAction")
|
||||||
: props.info.isVersionOlder
|
: props.info.isVersionOlder
|
||||||
? _("optionsBridgeOlderAction")
|
? _("optionsBridgeOlderAction")
|
||||||
: props.info.isVersionNewer
|
: props.info.isVersionNewer
|
||||||
? _("optionsBridgeNewerAction")
|
? _("optionsBridgeNewerAction")
|
||||||
: _("optionsBridgeNoAction")
|
: _("optionsBridgeNoAction")}
|
||||||
}
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
interface BridgeProps {
|
interface BridgeProps {
|
||||||
info?: BridgeInfo;
|
info?: BridgeInfo;
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
@@ -76,17 +82,17 @@ interface BridgeState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default class Bridge extends Component<BridgeProps, BridgeState> {
|
export default class Bridge extends Component<BridgeProps, BridgeState> {
|
||||||
private updateData: any;
|
private updateData?: Release;
|
||||||
private updateStatusTimeout?: number;
|
private updateStatusTimeout?: number;
|
||||||
|
|
||||||
constructor(props: BridgeProps) {
|
constructor(props: BridgeProps) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
isCheckingUpdates: false
|
isCheckingUpdates: false,
|
||||||
, isUpdateAvailable: false
|
isUpdateAvailable: false,
|
||||||
, wasErrorCheckingUpdates: false
|
wasErrorCheckingUpdates: false,
|
||||||
, checkUpdatesEllipsis: "..."
|
checkUpdatesEllipsis: "..."
|
||||||
};
|
};
|
||||||
|
|
||||||
this.onCheckUpdates = this.onCheckUpdates.bind(this);
|
this.onCheckUpdates = this.onCheckUpdates.bind(this);
|
||||||
@@ -96,97 +102,123 @@ export default class Bridge extends Component<BridgeProps, BridgeState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
const [ backupMessageStart, backupMessageEnd ] =
|
const [backupMessageStart, backupMessageEnd] = _(
|
||||||
_("optionsBridgeBackupEnabled", "\0").split("\0");
|
"optionsBridgeBackupEnabled",
|
||||||
|
"\0"
|
||||||
|
).split("\0");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="bridge">
|
<div className="bridge">
|
||||||
{ this.props.loading
|
{this.props.loading ? (
|
||||||
? ( <div className="bridge__loading">
|
<div className="bridge__loading">
|
||||||
{_("optionsBridgeLoading")}
|
{_("optionsBridgeLoading")}
|
||||||
<progress></progress>
|
<progress></progress>
|
||||||
</div> )
|
</div>
|
||||||
: this.renderStatus() }
|
) : (
|
||||||
|
this.renderStatus()
|
||||||
|
)}
|
||||||
|
|
||||||
{ !this.props.loading && this.props.options &&
|
{!this.props.loading && this.props.options && (
|
||||||
<div className="bridge__options">
|
<div className="bridge__options">
|
||||||
<label className="option option--inline">
|
<label className="option option--inline">
|
||||||
<div className="option__control">
|
<div className="option__control">
|
||||||
<input name="bridgeBackupEnabled"
|
<input
|
||||||
|
name="bridgeBackupEnabled"
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
checked={ this.props.options.bridgeBackupEnabled }
|
checked={
|
||||||
onChange={ this.props.onChange } />
|
this.props.options.bridgeBackupEnabled
|
||||||
|
}
|
||||||
|
onChange={this.props.onChange}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="option__label">
|
<div className="option__label">
|
||||||
{backupMessageStart}
|
{backupMessageStart}
|
||||||
<input className="bridge__backup-host"
|
<input
|
||||||
|
className="bridge__backup-host"
|
||||||
name="bridgeBackupHost"
|
name="bridgeBackupHost"
|
||||||
type="text"
|
type="text"
|
||||||
required
|
required
|
||||||
value={this.props.options.bridgeBackupHost}
|
value={this.props.options.bridgeBackupHost}
|
||||||
onChange={ this.props.onChange } />
|
onChange={this.props.onChange}
|
||||||
|
/>
|
||||||
:
|
:
|
||||||
<input className="bridge__backup-port"
|
<input
|
||||||
|
className="bridge__backup-port"
|
||||||
name="bridgeBackupPort"
|
name="bridgeBackupPort"
|
||||||
type="number"
|
type="number"
|
||||||
required
|
required
|
||||||
min="1025"
|
min="1025"
|
||||||
max="65535"
|
max="65535"
|
||||||
value={this.props.options.bridgeBackupPort}
|
value={this.props.options.bridgeBackupPort}
|
||||||
onChange={ this.props.onChange } />
|
onChange={this.props.onChange}
|
||||||
|
/>
|
||||||
{backupMessageEnd}
|
{backupMessageEnd}
|
||||||
</div>
|
</div>
|
||||||
<div className="option__description">
|
<div className="option__description">
|
||||||
{_("optionsBridgeBackupEnabledDescription")}
|
{_("optionsBridgeBackupEnabledDescription")}
|
||||||
</div>
|
</div>
|
||||||
</label>
|
</label>
|
||||||
</div> }
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{ !this.props.loading &&
|
{!this.props.loading && (
|
||||||
<div className="bridge__update-info">
|
<div className="bridge__update-info">
|
||||||
{ this.state.isUpdateAvailable
|
{this.state.isUpdateAvailable ? (
|
||||||
? ( <div className="bridge__update">
|
<div className="bridge__update">
|
||||||
<p className="bridge__update-label">
|
<p className="bridge__update-label">
|
||||||
{_("optionsBridgeUpdateAvailable")}
|
{_("optionsBridgeUpdateAvailable")}
|
||||||
</p>
|
</p>
|
||||||
<div className="bridge__update-options">
|
<div className="bridge__update-options">
|
||||||
<button className="bridge__update-start"
|
<button
|
||||||
|
className="bridge__update-start"
|
||||||
type="button"
|
type="button"
|
||||||
onClick={ this.onUpdate }>
|
onClick={this.onUpdate}
|
||||||
|
>
|
||||||
{_("optionsBridgeUpdate")}
|
{_("optionsBridgeUpdate")}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div> )
|
</div>
|
||||||
: ( <button className="bridge__update-check"
|
) : (
|
||||||
|
<button
|
||||||
|
className="bridge__update-check"
|
||||||
type="button"
|
type="button"
|
||||||
disabled={this.state.isCheckingUpdates}
|
disabled={this.state.isCheckingUpdates}
|
||||||
onClick={ this.onCheckUpdates }>
|
onClick={this.onCheckUpdates}
|
||||||
|
>
|
||||||
{this.state.isCheckingUpdates
|
{this.state.isCheckingUpdates
|
||||||
? _("optionsBridgeUpdateChecking"
|
? _(
|
||||||
, getNextEllipsis(this.state.checkUpdatesEllipsis))
|
"optionsBridgeUpdateChecking",
|
||||||
|
getNextEllipsis(
|
||||||
|
this.state.checkUpdatesEllipsis
|
||||||
|
)
|
||||||
|
)
|
||||||
: _("optionsBridgeUpdateCheck")}
|
: _("optionsBridgeUpdateCheck")}
|
||||||
</button> )}
|
</button>
|
||||||
|
)}
|
||||||
|
|
||||||
<div className="bridge--update-status">
|
<div className="bridge--update-status">
|
||||||
{ this.state.updateStatus && !this.state.isUpdateAvailable
|
{this.state.updateStatus &&
|
||||||
&& this.state.updateStatus }
|
!this.state.isUpdateAvailable &&
|
||||||
|
this.state.updateStatus}
|
||||||
</div>
|
</div>
|
||||||
</div> }
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private renderStatus() {
|
private renderStatus() {
|
||||||
const infoClasses = `bridge__info ${!this.props.info
|
const infoClasses = `bridge__info ${
|
||||||
|
!this.props.info
|
||||||
? this.props.loadingTimedOut
|
? this.props.loadingTimedOut
|
||||||
? "bridge__info--timed-out"
|
? "bridge__info--timed-out"
|
||||||
: "bridge__info--not-found"
|
: "bridge__info--not-found"
|
||||||
: "bridge__info--found"}`;
|
: "bridge__info--found"
|
||||||
|
}`;
|
||||||
|
|
||||||
let statusIcon: string;
|
let statusIcon: string;
|
||||||
let statusTitle: string;
|
let statusTitle: string;
|
||||||
let statusText: (string | null) = null;
|
let statusText: string | null = null;
|
||||||
|
|
||||||
if (this.props.loadingTimedOut) {
|
if (this.props.loadingTimedOut) {
|
||||||
statusIcon = "assets/icons8-warn-120.png";
|
statusIcon = "assets/icons8-warn-120.png";
|
||||||
@@ -208,22 +240,21 @@ export default class Bridge extends Component<BridgeProps, BridgeState> {
|
|||||||
return (
|
return (
|
||||||
<div className={infoClasses}>
|
<div className={infoClasses}>
|
||||||
<div className="bridge__status">
|
<div className="bridge__status">
|
||||||
<img className="bridge__status-icon"
|
<img
|
||||||
width="60" height="60"
|
className="bridge__status-icon"
|
||||||
src={ statusIcon } />
|
width="60"
|
||||||
|
height="60"
|
||||||
|
src={statusIcon}
|
||||||
|
/>
|
||||||
|
|
||||||
<h2 className="bridge__status-title">
|
<h2 className="bridge__status-title">{statusTitle}</h2>
|
||||||
{ statusTitle }
|
|
||||||
</h2>
|
|
||||||
|
|
||||||
{ statusText &&
|
{statusText && (
|
||||||
<p className="bridge__status-text">
|
<p className="bridge__status-text">{statusText}</p>
|
||||||
{ statusText }
|
)}
|
||||||
</p> }
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{ this.props.info &&
|
{this.props.info && <BridgeStats info={this.props.info} />}
|
||||||
<BridgeStats info={ this.props.info }/> }
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -236,7 +267,8 @@ export default class Bridge extends Component<BridgeProps, BridgeState> {
|
|||||||
const timeout = window.setInterval(() => {
|
const timeout = window.setInterval(() => {
|
||||||
this.setState(state => ({
|
this.setState(state => ({
|
||||||
checkUpdatesEllipsis: getNextEllipsis(
|
checkUpdatesEllipsis: getNextEllipsis(
|
||||||
state.checkUpdatesEllipsis)
|
state.checkUpdatesEllipsis
|
||||||
|
)
|
||||||
}));
|
}));
|
||||||
}, 500);
|
}, 500);
|
||||||
|
|
||||||
@@ -249,52 +281,58 @@ export default class Bridge extends Component<BridgeProps, BridgeState> {
|
|||||||
.catch(this.onCheckUpdatesError);
|
.catch(this.onCheckUpdatesError);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async onCheckUpdatesResponse(res: any) {
|
private async onCheckUpdatesResponse(res: Release[]) {
|
||||||
|
if (!Array.isArray(res)) {
|
||||||
|
throw logger.error("Check update response is not array.", res);
|
||||||
|
}
|
||||||
|
|
||||||
let latestBridgeRelease;
|
let latestBridgeRelease;
|
||||||
for (const release of res) {
|
for (const release of res) {
|
||||||
if (release.assets.find((asset: any) =>
|
if (
|
||||||
asset.content_type !== "application/x-xpinstall")) {
|
release.assets.find(
|
||||||
|
asset => asset.content_type !== "application/x-xpinstall"
|
||||||
|
)
|
||||||
|
) {
|
||||||
latestBridgeRelease = release;
|
latestBridgeRelease = release;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!latestBridgeRelease) {
|
if (!latestBridgeRelease) {
|
||||||
this.setState({
|
throw logger.error(
|
||||||
isCheckingUpdates: false
|
"Check update response does not contain release info."
|
||||||
, wasErrorCheckingUpdates: true
|
);
|
||||||
, updateStatus: _("optionsBridgeUpdateStatusError")
|
|
||||||
});
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const isUpdateAvailable = !this.props.info || semver.lt(
|
/**
|
||||||
this.props.info.version, latestBridgeRelease.tag_name);
|
* Update available if no bridge found or bridge version lower
|
||||||
|
* than fetched release version.
|
||||||
|
*/
|
||||||
|
const isUpdateAvailable =
|
||||||
|
!this.props.info ||
|
||||||
|
semver.lt(this.props.info.version, latestBridgeRelease.tag_name);
|
||||||
|
|
||||||
if (isUpdateAvailable) {
|
if (isUpdateAvailable) {
|
||||||
this.updateData = latestBridgeRelease;
|
this.updateData = latestBridgeRelease;
|
||||||
}
|
} else {
|
||||||
|
|
||||||
this.setState({
|
|
||||||
isCheckingUpdates: false
|
|
||||||
, isUpdateAvailable
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!isUpdateAvailable) {
|
|
||||||
this.setState({
|
this.setState({
|
||||||
updateStatus: _("optionsBridgeUpdateStatusNoUpdates")
|
updateStatus: _("optionsBridgeUpdateStatusNoUpdates")
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
isCheckingUpdates: false,
|
||||||
|
isUpdateAvailable
|
||||||
|
});
|
||||||
|
|
||||||
this.showUpdateStatus();
|
this.showUpdateStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
private onCheckUpdatesError() {
|
private onCheckUpdatesError() {
|
||||||
this.setState({
|
this.setState({
|
||||||
isCheckingUpdates: false
|
isCheckingUpdates: false,
|
||||||
, wasErrorCheckingUpdates: true
|
wasErrorCheckingUpdates: true,
|
||||||
, updateStatus: _("optionsBridgeUpdateStatusError")
|
updateStatus: _("optionsBridgeUpdateStatusError")
|
||||||
});
|
});
|
||||||
|
|
||||||
this.showUpdateStatus();
|
this.showUpdateStatus();
|
||||||
@@ -313,7 +351,7 @@ export default class Bridge extends Component<BridgeProps, BridgeState> {
|
|||||||
|
|
||||||
private async onUpdate() {
|
private async onUpdate() {
|
||||||
// Open downloads page
|
// Open downloads page
|
||||||
if (this.updateData.html_url) {
|
if (this.updateData?.html_url) {
|
||||||
browser.tabs.create({
|
browser.tabs.create({
|
||||||
url: this.updateData.html_url
|
url: this.updateData.html_url
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -565,8 +565,6 @@ class ReceiverEntry extends Component<ReceiverEntryProps, ReceiverEntryState> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const application = status.applications?.[0];
|
|
||||||
|
|
||||||
if (this.state.showAlternateAction) {
|
if (this.state.showAlternateAction) {
|
||||||
this.props.onStop(this.props.receiverDevice);
|
this.props.onStop(this.props.receiverDevice);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user