mirror of
https://gitlab.com/futo-org/fcast.git
synced 2025-06-24 21:25:23 +00:00
webOS: Ported receiver to Electron 2.1.0 changes
This commit is contained in:
parent
61c1e9a9c1
commit
e3c437a280
16 changed files with 2402 additions and 978 deletions
|
@ -1,6 +1,13 @@
|
|||
import { Opcode } from 'common/Packets';
|
||||
import { Logger, LoggerType } from 'common/Logger';
|
||||
|
||||
// Required for webOS since preload declared interface is not available on the backend
|
||||
declare global {
|
||||
interface Window {
|
||||
targetAPI: any;
|
||||
}
|
||||
}
|
||||
|
||||
// Window might be re-created while devices are still connected
|
||||
export function setUiUpdateCallbacks(callbacks: any) {
|
||||
const logger = window.targetAPI.logger;
|
||||
|
|
|
@ -157,7 +157,14 @@ export class Logger {
|
|||
|
||||
// @ts-ignore
|
||||
} else if (TARGET === 'webOS' || TARGET === 'tizenOS') {
|
||||
|
||||
this.funcTable = {
|
||||
trace: (message?: any, ...optionalParams: any[]) => console.trace(message, ...optionalParams),
|
||||
debug: (message?: any, ...optionalParams: any[]) => console.log(message, ...optionalParams),
|
||||
info: (message?: any, ...optionalParams: any[]) => console.log(message, ...optionalParams),
|
||||
warn: (message?: any, ...optionalParams: any[]) => console.warn(message, ...optionalParams),
|
||||
error: (message?: any, ...optionalParams: any[]) => console.error(message, ...optionalParams),
|
||||
fatal: (message?: any, ...optionalParams: any[]) => console.error(message, ...optionalParams),
|
||||
};
|
||||
} else {
|
||||
// @ts-ignore
|
||||
console.warn(`Attempting to initialize logger on unsupported target: ${TARGET}`);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import { Opcode } from 'common/Packets';
|
||||
import { Logger, LoggerType } from 'common/Logger';
|
||||
const logger = new Logger('MainWindow', LoggerType.FRONTEND);
|
||||
|
||||
|
@ -55,7 +54,14 @@ if (TARGET === 'electron') {
|
|||
window.targetAPI = {
|
||||
onDeviceInfo: (callback: () => void) => preloadData.onDeviceInfoCb = callback,
|
||||
getDeviceInfo: () => preloadData.deviceInfo,
|
||||
getSessions: (callback: () => any) => preloadData.getSessionsCb = callback,
|
||||
getSessions: (callback?: () => Promise<[any]>) => {
|
||||
if (callback) {
|
||||
preloadData.getSessionsCb = callback;
|
||||
}
|
||||
else {
|
||||
return preloadData.getSessionsCb();
|
||||
}
|
||||
},
|
||||
onConnect: (callback: (_, value: any) => void) => preloadData.onConnectCb = callback,
|
||||
onDisconnect: (callback: (_, value: any) => void) => preloadData.onDisconnectCb = callback,
|
||||
logger: loggerInterface,
|
||||
|
|
|
@ -75,7 +75,14 @@ if (TARGET === 'electron') {
|
|||
onSeek: (callback: any) => { preloadData.onSeekCb = callback; },
|
||||
onSetVolume: (callback: any) => { preloadData.onSetVolumeCb = callback; },
|
||||
onSetSpeed: (callback: any) => { preloadData.onSetSpeedCb = callback; },
|
||||
getSessions: (callback: any) => { preloadData.getSessionsCb = callback; },
|
||||
getSessions: (callback?: () => Promise<[any]>) => {
|
||||
if (callback) {
|
||||
preloadData.getSessionsCb = callback;
|
||||
}
|
||||
else {
|
||||
return preloadData.getSessionsCb();
|
||||
}
|
||||
},
|
||||
onConnect: (callback: any) => { preloadData.onConnectCb = callback; },
|
||||
onDisconnect: (callback: any) => { preloadData.onDisconnectCb = callback; },
|
||||
logger: loggerInterface,
|
||||
|
|
1232
receivers/webos/fcast-receiver-service/package-lock.json
generated
1232
receivers/webos/fcast-receiver-service/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "com.futo.fcast.receiver.service",
|
||||
"version": "1.0.1",
|
||||
"version": "1.1.0",
|
||||
"description": "FCast network service",
|
||||
"author": "FUTO",
|
||||
"license": "MIT",
|
||||
|
@ -11,7 +11,7 @@
|
|||
"postinstall": "patch-package"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.10.0",
|
||||
"@eslint/js": "^9.25.0",
|
||||
"@types/jest": "^29.5.11",
|
||||
"@types/mdns": "^0.0.38",
|
||||
"@types/node-forge": "^1.3.10",
|
||||
|
@ -19,9 +19,9 @@
|
|||
"@types/webos-service": "^0.4.6",
|
||||
"@types/webostvjs": "^1.2.6",
|
||||
"@types/ws": "^8.5.10",
|
||||
"copy-webpack-plugin": "^12.0.2",
|
||||
"eslint": "^9.10.0",
|
||||
"globals": "^15.9.0",
|
||||
"copy-webpack-plugin": "^13.0.0",
|
||||
"eslint": "^9.25.0",
|
||||
"globals": "^16.0.0",
|
||||
"jest": "^29.7.0",
|
||||
"mdns-js": "github:mdns-js/node-mdns-js",
|
||||
"patch-package": "^8.0.0",
|
||||
|
@ -29,15 +29,15 @@
|
|||
"ts-loader": "^9.4.2",
|
||||
"typescript": "^5.5.4",
|
||||
"typescript-eslint": "^8.4.0",
|
||||
"webpack": "^5.75.0",
|
||||
"webpack-cli": "^5.0.1"
|
||||
"webpack": "^5.99.6",
|
||||
"webpack-cli": "^6.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"http": "^0.0.1-security",
|
||||
"log4js": "^6.9.1",
|
||||
"url": "^0.11.3",
|
||||
"uuid": "^9.0.1",
|
||||
"ws": "^8.14.2"
|
||||
"url": "^0.11.4",
|
||||
"uuid": "^11.0.3",
|
||||
"ws": "^8.18.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"utf-8-validate": "^6.0.5"
|
||||
|
|
|
@ -10,30 +10,23 @@ import { DiscoveryService } from 'common/DiscoveryService';
|
|||
import { TcpListenerService } from 'common/TcpListenerService';
|
||||
import { WebSocketListenerService } from 'common/WebSocketListenerService';
|
||||
import { NetworkService } from 'common/NetworkService';
|
||||
import { ConnectionMonitor } from 'common/ConnectionMonitor';
|
||||
import { Logger, LoggerType } from 'common/Logger';
|
||||
import * as os from 'os';
|
||||
import * as log4js from "log4js";
|
||||
import { EventEmitter } from 'events';
|
||||
import { ToastIcon } from 'common/components/Toast';
|
||||
const logger = new Logger('Main', LoggerType.BACKEND);
|
||||
|
||||
export class Main {
|
||||
static tcpListenerService: TcpListenerService;
|
||||
static webSocketListenerService: WebSocketListenerService;
|
||||
static discoveryService: DiscoveryService;
|
||||
static logger: log4js.Logger;
|
||||
static connectionMonitor: ConnectionMonitor;
|
||||
static emitter: EventEmitter;
|
||||
|
||||
static {
|
||||
try {
|
||||
log4js.configure({
|
||||
appenders: {
|
||||
console: { type: 'console' },
|
||||
},
|
||||
categories: {
|
||||
default: { appenders: ['console'], level: 'info' },
|
||||
},
|
||||
});
|
||||
Main.logger = log4js.getLogger();
|
||||
Main.logger.info(`OS: ${process.platform} ${process.arch}`);
|
||||
logger.info(`OS: ${process.platform} ${process.arch}`);
|
||||
|
||||
const serviceId = 'com.futo.fcast.receiver.service';
|
||||
const service = new Service(serviceId);
|
||||
|
@ -50,19 +43,18 @@ export class Main {
|
|||
|
||||
registerService(service, 'toast', (message: any) => { return objectCb.bind(this, message) });
|
||||
|
||||
service.register("getDeviceInfo", (message: any) => {
|
||||
Main.logger.info("In getDeviceInfo callback");
|
||||
|
||||
// getDeviceInfo and network-changed handled in frontend
|
||||
service.register("get_sessions", (message: any) => {
|
||||
message.respond({
|
||||
returnValue: true,
|
||||
value: { name: os.hostname(), addresses: NetworkService.getAllIPv4Addresses() }
|
||||
value: [].concat(Main.tcpListenerService.getSenders(), Main.webSocketListenerService.getSessions())
|
||||
});
|
||||
});
|
||||
|
||||
registerService(service, 'connect', (message: any) => { return objectCb.bind(this, message) });
|
||||
registerService(service, 'disconnect', (message: any) => { return objectCb.bind(this, message) });
|
||||
registerService(service, 'ping', (message: any) => { return objectCb.bind(this, message) });
|
||||
|
||||
Main.connectionMonitor = new ConnectionMonitor();
|
||||
Main.discoveryService = new DiscoveryService();
|
||||
Main.discoveryService.start();
|
||||
|
||||
|
@ -93,7 +85,7 @@ export class Main {
|
|||
message.respond({ returnValue: true, value: { subscribed: true, playData: playData }});
|
||||
},
|
||||
(message: any) => {
|
||||
Main.logger.info('Canceled play service subscriber');
|
||||
logger.info('Canceled play service subscriber');
|
||||
Main.emitter.removeAllListeners('play');
|
||||
message.respond({ returnValue: true, value: message.payload });
|
||||
});
|
||||
|
@ -112,7 +104,7 @@ export class Main {
|
|||
message.respond({ returnValue: true, value: { subscribed: true }});
|
||||
},
|
||||
(message: any) => {
|
||||
Main.logger.info('Canceled stop service subscriber');
|
||||
logger.info('Canceled stop service subscriber');
|
||||
Main.emitter.removeAllListeners('stop');
|
||||
message.respond({ returnValue: true, value: message.payload });
|
||||
});
|
||||
|
@ -132,8 +124,8 @@ export class Main {
|
|||
'id': appId,
|
||||
'params': { timestamp: Date.now(), playData: message }
|
||||
}, (response: any) => {
|
||||
Main.logger.info(`Launch response: ${JSON.stringify(response)}`);
|
||||
Main.logger.info(`Relaunching FCast Receiver with args: ${JSON.stringify(message)}`);
|
||||
logger.info(`Launch response: ${JSON.stringify(response)}`);
|
||||
logger.info(`Relaunching FCast Receiver with args: ${JSON.stringify(message)}`);
|
||||
});
|
||||
});
|
||||
l.emitter.on("pause", () => Main.emitter.emit('pause'));
|
||||
|
@ -143,9 +135,22 @@ export class Main {
|
|||
l.emitter.on("setvolume", (message) => Main.emitter.emit('setvolume', message));
|
||||
l.emitter.on("setspeed", (message) => Main.emitter.emit('setspeed', message));
|
||||
|
||||
l.emitter.on('connect', (message) => Main.emitter.emit('connect', message));
|
||||
l.emitter.on('disconnect', (message) => Main.emitter.emit('disconnect', message));
|
||||
l.emitter.on('ping', (message) => Main.emitter.emit('ping', message));
|
||||
l.emitter.on('connect', (message) => {
|
||||
ConnectionMonitor.onConnect(l, message, l instanceof WebSocketListenerService, () => {
|
||||
Main.emitter.emit('connect', message);
|
||||
});
|
||||
});
|
||||
l.emitter.on('disconnect', (message) => {
|
||||
ConnectionMonitor.onDisconnect(l, message, l instanceof WebSocketListenerService, () => {
|
||||
Main.emitter.emit('disconnect', message);
|
||||
});
|
||||
});
|
||||
l.emitter.on('ping', (message) => {
|
||||
ConnectionMonitor.onPingPong(message, l instanceof WebSocketListenerService);
|
||||
});
|
||||
l.emitter.on('pong', (message) => {
|
||||
ConnectionMonitor.onPingPong(message, l instanceof WebSocketListenerService);
|
||||
});
|
||||
l.start();
|
||||
});
|
||||
|
||||
|
@ -159,7 +164,7 @@ export class Main {
|
|||
});
|
||||
|
||||
service.register("send_playback_update", (message: any) => {
|
||||
// Main.logger.info("In send_playback_update callback");
|
||||
// logger.info("In send_playback_update callback");
|
||||
|
||||
listeners.forEach(l => {
|
||||
const value: PlaybackUpdateMessage = message.payload.update;
|
||||
|
@ -179,7 +184,7 @@ export class Main {
|
|||
});
|
||||
}
|
||||
catch (err) {
|
||||
Main.logger.error("Error initializing service:", err);
|
||||
logger.error("Error initializing service:", err);
|
||||
Main.emitter.emit('toast', { message: `Error initializing service: ${err}`, icon: ToastIcon.ERROR });
|
||||
}
|
||||
|
||||
|
@ -190,9 +195,12 @@ export function getComputerName() {
|
|||
return os.hostname();
|
||||
}
|
||||
|
||||
export async function errorHandler(err: NodeJS.ErrnoException) {
|
||||
Main.logger.error("Application error:", err);
|
||||
Main.emitter.emit('toast', { message: err, icon: ToastIcon.ERROR });
|
||||
export async function errorHandler(error: Error) {
|
||||
logger.error(error);
|
||||
logger.shutdown();
|
||||
|
||||
logger.error("Application error:", error);
|
||||
Main.emitter.emit('toast', { message: error, icon: ToastIcon.ERROR });
|
||||
}
|
||||
|
||||
function registerService(service: Service, method: string, callback: (message: any) => any) {
|
||||
|
@ -206,7 +214,7 @@ function registerService(service: Service, method: string, callback: (message: a
|
|||
message.respond({ returnValue: true, value: { subscribed: true }});
|
||||
},
|
||||
(message: any) => {
|
||||
Main.logger.info(`Canceled ${method} service subscriber`);
|
||||
logger.info(`Canceled ${method} service subscriber`);
|
||||
Main.emitter.removeAllListeners(method);
|
||||
message.respond({ returnValue: true, value: message.payload });
|
||||
});
|
||||
|
|
|
@ -18,7 +18,7 @@ module.exports = [
|
|||
entry: {
|
||||
main: './src/Main.ts',
|
||||
},
|
||||
target: 'node',
|
||||
target: 'node8.12',
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"id": "com.futo.fcast.receiver",
|
||||
"version": "1.0.1",
|
||||
"version": "1.1.0",
|
||||
"vendor": "FUTO",
|
||||
"type": "web",
|
||||
"main": "main_window/index.html",
|
||||
|
|
1773
receivers/webos/fcast-receiver/package-lock.json
generated
1773
receivers/webos/fcast-receiver/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "com.futo.fcast.receiver",
|
||||
"version": "1.0.1",
|
||||
"version": "1.1.0",
|
||||
"description": "An application implementing a FCast receiver.",
|
||||
"author": "FUTO",
|
||||
"license": "MIT",
|
||||
|
@ -9,7 +9,7 @@
|
|||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.10.0",
|
||||
"@eslint/js": "^9.25.0",
|
||||
"@types/jest": "^29.5.11",
|
||||
"@types/mdns": "^0.0.38",
|
||||
"@types/node-forge": "^1.3.10",
|
||||
|
@ -17,17 +17,17 @@
|
|||
"@types/webostvjs": "^1.2.6",
|
||||
"@types/workerpool": "^6.1.1",
|
||||
"@types/ws": "^8.5.10",
|
||||
"copy-webpack-plugin": "^12.0.2",
|
||||
"eslint": "^9.10.0",
|
||||
"globals": "^15.9.0",
|
||||
"copy-webpack-plugin": "^13.0.0",
|
||||
"eslint": "^9.25.0",
|
||||
"globals": "^16.0.0",
|
||||
"jest": "^29.7.0",
|
||||
"mdns-js": "github:mdns-js/node-mdns-js",
|
||||
"ts-jest": "^29.1.1",
|
||||
"ts-loader": "^9.4.2",
|
||||
"typescript": "^5.5.4",
|
||||
"typescript-eslint": "^8.4.0",
|
||||
"webpack": "^5.75.0",
|
||||
"webpack-cli": "^5.0.1"
|
||||
"webpack": "^5.99.6",
|
||||
"webpack-cli": "^6.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"bufferutil": "^4.0.8",
|
||||
|
@ -35,10 +35,9 @@
|
|||
"hls.js": "^1.5.15",
|
||||
"http": "^0.0.1-security",
|
||||
"https": "^1.0.0",
|
||||
"log4js": "^6.9.1",
|
||||
"qrcode": "^1.5.3",
|
||||
"url": "^0.11.3",
|
||||
"uuid": "^9.0.1",
|
||||
"ws": "^8.14.2"
|
||||
"url": "^0.11.4",
|
||||
"uuid": "^11.0.3",
|
||||
"ws": "^8.18.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import { preloadData } from 'common/main/Preload';
|
|||
import { toast, ToastIcon } from 'common/components/Toast';
|
||||
require('lib/webOSTVjs-1.2.10/webOSTV.js');
|
||||
require('lib/webOSTVjs-1.2.10/webOSTV-dev.js');
|
||||
const logger = window.targetAPI.logger;
|
||||
|
||||
enum RemoteKeyCode {
|
||||
Stop = 413,
|
||||
|
@ -15,24 +16,57 @@ enum RemoteKeyCode {
|
|||
}
|
||||
|
||||
try {
|
||||
const toastService = registerService('toast', (message: any) => { toast(message.value.message, message.value.icon, message.value.duration); });
|
||||
const getDeviceInfoService = registerService('getDeviceInfo', (message: any) => {
|
||||
console.log(`Main: getDeviceInfo ${JSON.stringify(message)}`);
|
||||
preloadData.deviceInfo = message.value;
|
||||
preloadData.onDeviceInfoCb();
|
||||
}, false);
|
||||
const onConnectService = registerService('connect', (message: any) => { preloadData.onConnectCb(null, message.value); });
|
||||
const onDisconnectService = registerService('disconnect', (message: any) => { preloadData.onDisconnectCb(null, message.value); });
|
||||
const onPingService = registerService('ping', (message: any) => { preloadData.onPingCb(null, message.value); });
|
||||
const playService = registerService('play', (message: any) => {
|
||||
let getSessions = null;
|
||||
|
||||
const toastService = requestService('toast', (message: any) => { toast(message.value.message, message.value.icon, message.value.duration); });
|
||||
const getDeviceInfoService = window.webOS.service.request('luna://com.palm.connectionmanager', {
|
||||
method: 'getStatus',
|
||||
parameters: {},
|
||||
onSuccess: (message: any) => {
|
||||
// logger.info('Network info status message', message);
|
||||
const deviceName = 'FCast-LGwebOSTV';
|
||||
const connections = [];
|
||||
|
||||
if (message.wired.state !== 'disconnected') {
|
||||
connections.push({ type: 'wired', name: 'Ethernet', address: message.wired.ipAddress })
|
||||
}
|
||||
|
||||
// wifiDirect never seems to be connected, despite being connected (which is needed for signalLevel...)
|
||||
// if (message.wifiDirect.state !== 'disconnected') {
|
||||
if (message.wifi.state !== 'disconnected') {
|
||||
connections.push({ type: 'wireless', name: message.wifi.ssid, address: message.wifi.ipAddress, signalLevel: 100 })
|
||||
}
|
||||
|
||||
preloadData.deviceInfo = { name: deviceName, interfaces: connections };
|
||||
preloadData.onDeviceInfoCb();
|
||||
},
|
||||
onFailure: (message: any) => {
|
||||
logger.error(`Main: com.palm.connectionmanager/getStatus ${JSON.stringify(message)}`);
|
||||
toast(`Main: com.palm.connectionmanager/getStatus ${JSON.stringify(message)}`, ToastIcon.ERROR);
|
||||
|
||||
},
|
||||
// onComplete: (message) => {},
|
||||
subscribe: true,
|
||||
resubscribe: true
|
||||
});
|
||||
|
||||
window.targetAPI.getSessions(() => {
|
||||
return new Promise((resolve, reject) => {
|
||||
getSessions = requestService('get_sessions', (message: any) => resolve(message.value), (message: any) => reject(message), false);
|
||||
});
|
||||
});
|
||||
|
||||
const onConnectService = requestService('connect', (message: any) => { preloadData.onConnectCb(null, message.value); });
|
||||
const onDisconnectService = requestService('disconnect', (message: any) => { preloadData.onDisconnectCb(null, message.value); });
|
||||
const playService = requestService('play', (message: any) => {
|
||||
if (message.value !== undefined && message.value.playData !== undefined) {
|
||||
console.log(`Main: Playing ${JSON.stringify(message)}`);
|
||||
logger.info(`Main: Playing ${JSON.stringify(message)}`);
|
||||
sessionStorage.setItem('playData', JSON.stringify(message.value.playData));
|
||||
getDeviceInfoService.cancel();
|
||||
getSessions?.cancel();
|
||||
toastService.cancel();
|
||||
onConnectService.cancel();
|
||||
onDisconnectService.cancel();
|
||||
onPingService.cancel();
|
||||
playService.cancel();
|
||||
|
||||
// WebOS 22 and earlier does not work well using the history API,
|
||||
|
@ -44,7 +78,7 @@ try {
|
|||
|
||||
const launchHandler = () => {
|
||||
const params = window.webOSDev.launchParams();
|
||||
console.log(`Main: (Re)launching FCast Receiver with args: ${JSON.stringify(params)}`);
|
||||
logger.info(`Main: (Re)launching FCast Receiver with args: ${JSON.stringify(params)}`);
|
||||
|
||||
const lastTimestamp = Number(localStorage.getItem('lastTimestamp'));
|
||||
if (params.playData !== undefined && params.timestamp != lastTimestamp) {
|
||||
|
@ -52,9 +86,9 @@ try {
|
|||
sessionStorage.setItem('playData', JSON.stringify(params.playData));
|
||||
toastService?.cancel();
|
||||
getDeviceInfoService?.cancel();
|
||||
getSessions?.cancel();
|
||||
onConnectService?.cancel();
|
||||
onDisconnectService?.cancel();
|
||||
onPingService?.cancel();
|
||||
playService?.cancel();
|
||||
|
||||
// WebOS 22 and earlier does not work well using the history API,
|
||||
|
@ -73,7 +107,7 @@ try {
|
|||
// };
|
||||
|
||||
document.addEventListener('keydown', (event: any) => {
|
||||
// console.log("KeyDown", event);
|
||||
// logger.info("KeyDown", event);
|
||||
|
||||
switch (event.keyCode) {
|
||||
// WebOS 22 and earlier does not work well using the history API,
|
||||
|
@ -87,11 +121,11 @@ try {
|
|||
});
|
||||
}
|
||||
catch (err) {
|
||||
console.error(`Main: preload ${JSON.stringify(err)}`);
|
||||
toast(`Main: preload ${JSON.stringify(err)}`, ToastIcon.ERROR);
|
||||
logger.error(`Main: preload ${JSON.stringify(err)}`);
|
||||
toast(`Error starting the application (preload): ${JSON.stringify(err)}`, ToastIcon.ERROR);
|
||||
}
|
||||
|
||||
function registerService(method: string, callback: (message: any) => void, subscribe: boolean = true): any {
|
||||
function requestService(method: string, successCallback: (message: any) => void, failureCallback?: (message: any) => void, subscribe: boolean = true): any {
|
||||
const serviceId = 'com.futo.fcast.receiver.service';
|
||||
|
||||
return window.webOS.service.request(`luna://${serviceId}/`, {
|
||||
|
@ -99,15 +133,18 @@ function registerService(method: string, callback: (message: any) => void, subsc
|
|||
parameters: {},
|
||||
onSuccess: (message: any) => {
|
||||
if (message.value?.subscribed === true) {
|
||||
console.log(`Main: Registered ${method} handler with service`);
|
||||
logger.info(`Main: Registered ${method} handler with service`);
|
||||
}
|
||||
else {
|
||||
callback(message);
|
||||
successCallback(message);
|
||||
}
|
||||
},
|
||||
onFailure: (message: any) => {
|
||||
console.error(`Main: ${method} ${JSON.stringify(message)}`);
|
||||
toast(`Main: ${method} ${JSON.stringify(message)}`, ToastIcon.ERROR);
|
||||
logger.error(`Main: ${method} ${JSON.stringify(message)}`);
|
||||
|
||||
if (failureCallback) {
|
||||
failureCallback(message);
|
||||
}
|
||||
},
|
||||
// onComplete: (message) => {},
|
||||
subscribe: subscribe,
|
||||
|
|
|
@ -1,15 +1,14 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>FCast Receiver</title>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<link rel="stylesheet" href="../assets/fonts/outfit.css" />
|
||||
<link rel="stylesheet" href="../assets/fonts/inter.css" />
|
||||
<link rel="stylesheet" href="./common.css" />
|
||||
<link rel="stylesheet" href="./style.css" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="loading-screen">
|
||||
<div id="loading-text" class="non-selectable">Loading FCast</div>
|
||||
|
@ -34,16 +33,34 @@
|
|||
</div>
|
||||
</div>
|
||||
<div id="detail-view" class="card">
|
||||
<div class="non-selectable card-title">Manual connection information</div>
|
||||
<div class="non-selectable card-title">Connection Information</div>
|
||||
<div class="card-title-separator"></div>
|
||||
<div>
|
||||
<div id="ips">IPs</div><br />
|
||||
<div id="ip-ports">Port<br>46899 (TCP), 46898 (WS)</div>
|
||||
|
||||
<div id="connection-information-loading">
|
||||
<div id="connection-information-loading-text" class="lds-ring">Fetching Network Info...</div>
|
||||
<div id="connection-information-loading-spinner" class="lds-ring"><div></div><div></div><div></div><div></div></div>
|
||||
</div>
|
||||
<div id="connection-error">
|
||||
<div id="connection-error-icon"></div>
|
||||
<div id="connection-error-text">Device not connected to a network</div>
|
||||
</div>
|
||||
<div id="connection-information">
|
||||
<div id="scan-to-connect" class="non-selectable">Scan with a FCast sender app</div>
|
||||
<canvas id="qr-code"></canvas>
|
||||
<div id="app-download" class="non-selectable app-download">Need a sender app?<br>Download Grayjay at <a href="https://grayjay.app" target="_blank">https://grayjay.app</a></div>
|
||||
|
||||
<br />
|
||||
<div id="connection-details" class="non-selectable card-title">Connection Details</div>
|
||||
<div id="connection-details-separator" class="card-title-separator"></div>
|
||||
<div>
|
||||
<div id="ips">
|
||||
<div id="ips-iface-icon"></div>
|
||||
<div id="ips-iface-text"></div>
|
||||
<div id="ips-iface-name"></div>
|
||||
</div><br />
|
||||
<div id="ip-ports">Port<br>46899 (TCP), 46898 (WS)</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="automatic-discovery" class="non-selectable">Automatic discovery is available via mDNS</div>
|
||||
<canvas id="qr-code"></canvas>
|
||||
<div id="scan-to-connect" class="non-selectable">Scan with a FCast sender app.</div>
|
||||
<div id="app-download" class="non-selectable app-download">Need a sender app?<br>Download Grayjay at <u class="app-download">https://grayjay.app</u></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -57,5 +74,4 @@
|
|||
<script src="./preload.js"></script>
|
||||
<script src="./renderer.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
|
@ -4,15 +4,11 @@
|
|||
|
||||
#overlay {
|
||||
font-family: InterRegular;
|
||||
font-size: 28px;
|
||||
|
||||
/* gap not supported in WebOS 6.0 */
|
||||
gap: unset;
|
||||
}
|
||||
|
||||
#main-view {
|
||||
padding: 25px;
|
||||
|
||||
/* gap not supported in WebOS 6.0 */
|
||||
gap: unset;
|
||||
margin-right: 15vw;
|
||||
|
@ -20,16 +16,6 @@
|
|||
|
||||
#title-text {
|
||||
font-family: OutfitExtraBold;
|
||||
font-size: 140px;
|
||||
}
|
||||
|
||||
#title-icon {
|
||||
width: 124px;
|
||||
height: 124px;
|
||||
}
|
||||
|
||||
#manual-connection-info {
|
||||
font-family: InterBold;
|
||||
}
|
||||
|
||||
#scan-to-connect {
|
||||
|
@ -43,16 +29,6 @@
|
|||
|
||||
#window-can-be-closed {
|
||||
font-family: InterRegular;
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.lds-ring {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
}
|
||||
.lds-ring div {
|
||||
width: 104px;
|
||||
height: 104px;
|
||||
}
|
||||
|
||||
#loading-screen {
|
||||
|
@ -74,23 +50,10 @@
|
|||
padding-right: 20px;
|
||||
}
|
||||
|
||||
#connection-check {
|
||||
width: 104px;
|
||||
height: 104px;
|
||||
}
|
||||
|
||||
#toast-notification {
|
||||
gap: unset;
|
||||
top: -250px;
|
||||
}
|
||||
|
||||
#toast-icon {
|
||||
width: 88px;
|
||||
height: 88px;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
#toast-text {
|
||||
font-family: InterRegular;
|
||||
font-size: 28px;
|
||||
}
|
||||
|
|
|
@ -5,9 +5,12 @@ import { PlaybackErrorMessage, PlaybackUpdateMessage, VolumeUpdateMessage } from
|
|||
import { toast, ToastIcon } from 'common/components/Toast';
|
||||
require('lib/webOSTVjs-1.2.10/webOSTV.js');
|
||||
require('lib/webOSTVjs-1.2.10/webOSTV-dev.js');
|
||||
const logger = window.targetAPI.logger;
|
||||
|
||||
try {
|
||||
const serviceId = 'com.futo.fcast.receiver.service';
|
||||
let getSessions = null;
|
||||
|
||||
window.webOSAPI = {
|
||||
pendingPlay: JSON.parse(sessionStorage.getItem('playData'))
|
||||
};
|
||||
|
@ -18,7 +21,7 @@ try {
|
|||
parameters: { error },
|
||||
onSuccess: () => {},
|
||||
onFailure: (message: any) => {
|
||||
console.error(`Player: send_playback_error ${JSON.stringify(message)}`);
|
||||
logger.error(`Player: send_playback_error ${JSON.stringify(message)}`);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
@ -27,11 +30,11 @@ try {
|
|||
method: 'send_playback_update',
|
||||
parameters: { update },
|
||||
// onSuccess: (message: any) => {
|
||||
// console.log(`Player: send_playback_update ${JSON.stringify(message)}`);
|
||||
// logger.info(`Player: send_playback_update ${JSON.stringify(message)}`);
|
||||
// },
|
||||
onSuccess: () => {},
|
||||
onFailure: (message: any) => {
|
||||
console.error(`Player: send_playback_update ${JSON.stringify(message)}`);
|
||||
logger.error(`Player: send_playback_update ${JSON.stringify(message)}`);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
@ -41,7 +44,7 @@ try {
|
|||
parameters: { update },
|
||||
onSuccess: () => {},
|
||||
onFailure: (message: any) => {
|
||||
console.error(`Player: send_volume_update ${JSON.stringify(message)}`);
|
||||
logger.error(`Player: send_volume_update ${JSON.stringify(message)}`);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
@ -50,9 +53,9 @@ try {
|
|||
method:"play",
|
||||
parameters: {},
|
||||
onSuccess: (message: any) => {
|
||||
// console.log(JSON.stringify(message));
|
||||
// logger.info(JSON.stringify(message));
|
||||
if (message.value.subscribed === true) {
|
||||
console.log('Player: Registered play handler with service');
|
||||
logger.info('Player: Registered play handler with service');
|
||||
}
|
||||
|
||||
if (message.value.playData !== null) {
|
||||
|
@ -65,15 +68,15 @@ try {
|
|||
}
|
||||
},
|
||||
onFailure: (message: any) => {
|
||||
console.error(`Player: play ${JSON.stringify(message)}`);
|
||||
logger.error(`Player: play ${JSON.stringify(message)}`);
|
||||
},
|
||||
subscribe: true,
|
||||
resubscribe: true
|
||||
});
|
||||
|
||||
const pauseService = registerService('pause', () => { preloadData.onPauseCb(); });
|
||||
const resumeService = registerService('resume', () => { preloadData.onResumeCb(); });
|
||||
const stopService = registerService('stop', () => {
|
||||
const pauseService = requestService('pause', () => { preloadData.onPauseCb(); });
|
||||
const resumeService = requestService('resume', () => { preloadData.onResumeCb(); });
|
||||
const stopService = requestService('stop', () => {
|
||||
playService.cancel();
|
||||
pauseService.cancel();
|
||||
resumeService.cancel();
|
||||
|
@ -81,6 +84,9 @@ try {
|
|||
seekService.cancel();
|
||||
setVolumeService.cancel();
|
||||
setSpeedService.cancel();
|
||||
getSessions?.cancel();
|
||||
onConnectService.cancel();
|
||||
onDisconnectService.cancel();
|
||||
|
||||
// WebOS 22 and earlier does not work well using the history API,
|
||||
// so manually handling page navigation...
|
||||
|
@ -88,14 +94,23 @@ try {
|
|||
window.open('../main_window/index.html', '_self');
|
||||
});
|
||||
|
||||
const seekService = registerService('seek', (message: any) => { preloadData.onSeekCb(null, message.value); });
|
||||
const setVolumeService = registerService('setvolume', (message: any) => { preloadData.onSetVolumeCb(null, message.value); });
|
||||
const setSpeedService = registerService('setspeed', (message: any) => { preloadData.onSetSpeedCb(null, message.value); });
|
||||
const seekService = requestService('seek', (message: any) => { preloadData.onSeekCb(null, message.value); });
|
||||
const setVolumeService = requestService('setvolume', (message: any) => { preloadData.onSetVolumeCb(null, message.value); });
|
||||
const setSpeedService = requestService('setspeed', (message: any) => { preloadData.onSetSpeedCb(null, message.value); });
|
||||
|
||||
window.targetAPI.getSessions(() => {
|
||||
return new Promise((resolve, reject) => {
|
||||
getSessions = requestService('get_sessions', (message: any) => resolve(message.value), (message: any) => reject(message), false);
|
||||
});
|
||||
});
|
||||
|
||||
const onConnectService = requestService('connect', (message: any) => { preloadData.onConnectCb(null, message.value); });
|
||||
const onDisconnectService = requestService('disconnect', (message: any) => { preloadData.onDisconnectCb(null, message.value); });
|
||||
|
||||
const launchHandler = () => {
|
||||
// args don't seem to be passed in via event despite what documentation says...
|
||||
const params = window.webOSDev.launchParams();
|
||||
console.log(`Player: (Re)launching FCast Receiver with args: ${JSON.stringify(params)}`);
|
||||
logger.info(`Player: (Re)launching FCast Receiver with args: ${JSON.stringify(params)}`);
|
||||
|
||||
const lastTimestamp = Number(localStorage.getItem('lastTimestamp'));
|
||||
if (params.playData !== undefined && params.timestamp != lastTimestamp) {
|
||||
|
@ -108,6 +123,9 @@ try {
|
|||
seekService?.cancel();
|
||||
setVolumeService?.cancel();
|
||||
setSpeedService?.cancel();
|
||||
getSessions?.cancel();
|
||||
onConnectService?.cancel();
|
||||
onDisconnectService?.cancel();
|
||||
|
||||
// WebOS 22 and earlier does not work well using the history API,
|
||||
// so manually handling page navigation...
|
||||
|
@ -121,27 +139,30 @@ try {
|
|||
|
||||
}
|
||||
catch (err) {
|
||||
console.error(`Player: preload ${JSON.stringify(err)}`);
|
||||
toast(`Player: preload ${JSON.stringify(err)}`, ToastIcon.ERROR);
|
||||
logger.error(`Player: preload ${JSON.stringify(err)}`);
|
||||
toast(`Error starting the video player (preload): ${JSON.stringify(err)}`, ToastIcon.ERROR);
|
||||
}
|
||||
|
||||
function registerService(method: string, callback: (message: any) => void, subscribe: boolean = true): any {
|
||||
function requestService(method: string, successCallback: (message: any) => void, failureCallback?: (message: any) => void, subscribe: boolean = true): any {
|
||||
const serviceId = 'com.futo.fcast.receiver.service';
|
||||
|
||||
return window.webOS.service.request(`luna://${serviceId}/`, {
|
||||
method: method,
|
||||
parameters: {},
|
||||
onSuccess: (message: any) => {
|
||||
if (message.value.subscribed === true) {
|
||||
console.log(`Player: Registered ${method} handler with service`);
|
||||
if (message.value?.subscribed === true) {
|
||||
logger.info(`Player: Registered ${method} handler with service`);
|
||||
}
|
||||
else {
|
||||
callback(message);
|
||||
successCallback(message);
|
||||
}
|
||||
},
|
||||
onFailure: (message: any) => {
|
||||
console.error(`Player: ${method} ${JSON.stringify(message)}`);
|
||||
// toast(`Player: ${method} ${JSON.stringify(message)}`, ToastIcon.ERROR);
|
||||
logger.error(`Main: ${method} ${JSON.stringify(message)}`);
|
||||
|
||||
if (failureCallback) {
|
||||
failureCallback(message);
|
||||
}
|
||||
},
|
||||
// onComplete: (message) => {},
|
||||
subscribe: subscribe,
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
<head>
|
||||
<title>FCast Receiver</title>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<link rel="stylesheet" href="../assets/fonts/inter.css" />
|
||||
<link rel="stylesheet" href="./common.css" />
|
||||
<link rel="stylesheet" href="./style.css" />
|
||||
|
@ -93,6 +94,11 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div id="toast-notification">
|
||||
<div id="toast-icon"></div>
|
||||
<div id="toast-text"></div>
|
||||
</div>
|
||||
|
||||
<script src="./renderer.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue