lg-dev-manager-bridge 1.0.3 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js
CHANGED
|
@@ -124,7 +124,9 @@ var AppsErrorCodes = {
|
|
|
124
124
|
FileTooLarge: "file_too_large",
|
|
125
125
|
TransferFailed: "transfer_failed",
|
|
126
126
|
/** Another app with this id is installed outside the developer partition (e.g. from the LG Content Store). */
|
|
127
|
-
Conflict: "app_conflict"
|
|
127
|
+
Conflict: "app_conflict",
|
|
128
|
+
/** The TV is in standby: apps can be installed, updated and removed, but a launch would show nothing. */
|
|
129
|
+
TvOff: "tv_off"
|
|
128
130
|
};
|
|
129
131
|
|
|
130
132
|
// ../../packages/protocol/src/console.ts
|
|
@@ -335,6 +337,7 @@ var LitefinErrorCodes = {
|
|
|
335
337
|
var PROTOCOL_VERSION = 8;
|
|
336
338
|
var base64 = z9.string().regex(/^[A-Za-z0-9+/]*={0,2}$/, "Not base64");
|
|
337
339
|
var DEFAULT_BRIDGE_PORT = 5199;
|
|
340
|
+
var TvPowerState = z9.enum(["on", "screenOff", "standby", "unknown"]);
|
|
338
341
|
var Methods = {
|
|
339
342
|
/** First message on every connection. Authenticates with the pairing token. */
|
|
340
343
|
"system.hello": {
|
|
@@ -404,6 +407,15 @@ var Methods = {
|
|
|
404
407
|
socName: z9.string().optional()
|
|
405
408
|
})
|
|
406
409
|
},
|
|
410
|
+
/**
|
|
411
|
+
* Is the TV on? `com.webos.service.tvpower/power/getPowerState`: `on` (also with the screen saver), `screenOff` (on,
|
|
412
|
+
* picture turned off), `standby` (looks off — the system still runs, so installs work, but nothing can be shown),
|
|
413
|
+
* `unknown` (the TV didn't say; treat as on). `raw` is the TV's own state text.
|
|
414
|
+
*/
|
|
415
|
+
"device.power": {
|
|
416
|
+
params: z9.object({ device: DeviceTarget }),
|
|
417
|
+
result: z9.object({ state: TvPowerState, raw: z9.string().optional() })
|
|
418
|
+
},
|
|
407
419
|
/** `df` of a folder (KiB; default the developer partition). Null if the TV gave no usable answer. */
|
|
408
420
|
"device.storage": {
|
|
409
421
|
params: z9.object({ device: DeviceTarget, path: RemotePath.optional() }),
|
|
@@ -892,7 +904,7 @@ import { platform } from "node:os";
|
|
|
892
904
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
893
905
|
|
|
894
906
|
// src/version.ts
|
|
895
|
-
var BRIDGE_VERSION = "1.0.
|
|
907
|
+
var BRIDGE_VERSION = "1.0.4";
|
|
896
908
|
|
|
897
909
|
// src/ssh/logged.ts
|
|
898
910
|
import { randomUUID } from "node:crypto";
|
|
@@ -1777,6 +1789,39 @@ async function renewDevMode(pool, device) {
|
|
|
1777
1789
|
await lunaCall(pool, device, "luna://com.webos.applicationManager/launch", { id: "com.palmdts.devmode", subscribe: false, params: { extend: true } }, true);
|
|
1778
1790
|
}
|
|
1779
1791
|
|
|
1792
|
+
// src/devices/power.ts
|
|
1793
|
+
var GET_POWER_STATE = "luna://com.webos.service.tvpower/power/getPowerState";
|
|
1794
|
+
var TURN_ON_SCREEN = "luna://com.webos.service.tvpower/power/turnOnScreen";
|
|
1795
|
+
function powerStateOf(msg) {
|
|
1796
|
+
const state = typeof msg.state === "string" ? msg.state : "";
|
|
1797
|
+
const processing = typeof msg.processing === "string" ? msg.processing : "";
|
|
1798
|
+
if (/power ?off|suspend|standby/i.test(processing)) return "standby";
|
|
1799
|
+
if (state === "Active" || state === "Screen Saver") return "on";
|
|
1800
|
+
if (state === "Screen Off") return "screenOff";
|
|
1801
|
+
if (/standby|suspend|power ?off/i.test(state)) return "standby";
|
|
1802
|
+
return "unknown";
|
|
1803
|
+
}
|
|
1804
|
+
async function tvPower(pool, device) {
|
|
1805
|
+
for (const pub of device.username === "root" ? [true, false] : [true]) {
|
|
1806
|
+
try {
|
|
1807
|
+
const msg = await lunaCall(pool, device, GET_POWER_STATE, {}, pub);
|
|
1808
|
+
return { state: powerStateOf(msg), raw: [msg.state, msg.processing].filter((v) => typeof v === "string").join(" \xB7 ") || void 0 };
|
|
1809
|
+
} catch {
|
|
1810
|
+
}
|
|
1811
|
+
}
|
|
1812
|
+
return { state: "unknown" };
|
|
1813
|
+
}
|
|
1814
|
+
async function turnOnScreen(pool, device) {
|
|
1815
|
+
for (const pub of device.username === "root" ? [true, false] : [true]) {
|
|
1816
|
+
try {
|
|
1817
|
+
await lunaCall(pool, device, TURN_ON_SCREEN, {}, pub);
|
|
1818
|
+
return true;
|
|
1819
|
+
} catch {
|
|
1820
|
+
}
|
|
1821
|
+
}
|
|
1822
|
+
return false;
|
|
1823
|
+
}
|
|
1824
|
+
|
|
1780
1825
|
// src/apps/apps.ts
|
|
1781
1826
|
import { createHash as createHash3 } from "node:crypto";
|
|
1782
1827
|
import { posix } from "node:path";
|
|
@@ -1942,7 +1987,16 @@ async function listApps(pool, device) {
|
|
|
1942
1987
|
});
|
|
1943
1988
|
}
|
|
1944
1989
|
async function launchApp(pool, device, id, params) {
|
|
1990
|
+
const power = await tvPower(pool, device);
|
|
1991
|
+
if (power.state === "standby") {
|
|
1992
|
+
throw new RpcError(
|
|
1993
|
+
AppsErrorCodes.TvOff,
|
|
1994
|
+
"The TV is off (in standby). Turn it on with the remote, then launch the app. Installing, updating and removing apps work while it\u2019s off.",
|
|
1995
|
+
power.raw ? `getPowerState: ${power.raw}` : void 0
|
|
1996
|
+
);
|
|
1997
|
+
}
|
|
1945
1998
|
await lunaCall(pool, device, "luna://com.webos.applicationManager/launch", { id, subscribe: false, params }, true);
|
|
1999
|
+
if (power.state === "screenOff") await turnOnScreen(pool, device);
|
|
1946
2000
|
}
|
|
1947
2001
|
async function appIcon(pool, device, path) {
|
|
1948
2002
|
const mime = ICON_TYPES[posix.extname(path).toLowerCase()];
|
|
@@ -2681,6 +2735,8 @@ var handlers = {
|
|
|
2681
2735
|
},
|
|
2682
2736
|
"device.info": ({ device, quiet }, session, ctx) => deviceInfo(sshFor(session, ctx, quiet), device),
|
|
2683
2737
|
"device.storage": ({ device, path }, session, ctx) => storageInfo(sshFor(session, ctx), device, path),
|
|
2738
|
+
// Polled by the apps pages: a background read in the console.
|
|
2739
|
+
"device.power": ({ device }, session, ctx) => tvPower(sshFor(session, ctx, true), device),
|
|
2684
2740
|
"device.generateKey": ({ comment }) => generateKey(comment),
|
|
2685
2741
|
// The token is read through the plain pool so it never appears in the console; the LG request is traced
|
|
2686
2742
|
// with the token blanked out.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lg-dev-manager-bridge",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
4
4
|
"description": "Local bridge for LG Dev Manager: lets the web app at lg.scoty.uk (or its local copy) manage LG webOS TVs over SSH",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Scoty (https://github.com/Scoty)",
|
|
@@ -51,8 +51,8 @@
|
|
|
51
51
|
"tsx": "^4.20.0",
|
|
52
52
|
"typescript": "^5.9.0",
|
|
53
53
|
"vitest": "^4.1.11",
|
|
54
|
-
"@lgdm/mock-tv": "1.0.
|
|
55
|
-
"@lgdm/protocol": "1.0.
|
|
54
|
+
"@lgdm/mock-tv": "1.0.4",
|
|
55
|
+
"@lgdm/protocol": "1.0.4"
|
|
56
56
|
},
|
|
57
57
|
"scripts": {
|
|
58
58
|
"dev": "tsx watch src/cli.ts --dev",
|