@tomorrowos/sdk 0.9.11 → 0.9.13
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/REPLIT_SETUP.md +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/store/postgres-store.d.ts.map +1 -1
- package/dist/store/postgres-store.js +13 -5
- package/dist/store/sqlite-store.d.ts.map +1 -1
- package/dist/store/sqlite-store.js +10 -5
- package/dist/store/types.d.ts +10 -0
- package/dist/store/types.d.ts.map +1 -1
- package/dist/tomorrowos.d.ts +13 -1
- package/dist/tomorrowos.d.ts.map +1 -1
- package/dist/tomorrowos.js +76 -1
- package/package.json +1 -1
- package/templates/cms-starter/package.json +2 -2
- package/templates/cms-starter/public/index.html +29 -0
- package/templates/cms-starter/public/methods.js +115 -1
- package/templates/cms-starter/public/panel.css +24 -0
package/REPLIT_SETUP.md
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ export type { DeviceListItem, DeviceScreenshotInfo, ListenOptions, TomorrowOSBra
|
|
|
3
3
|
export type { ConnectorState, ConnectorStatus, ServerStatusReport, StatusBlocker } from "./server-status.js";
|
|
4
4
|
export { buildServerStatus } from "./server-status.js";
|
|
5
5
|
export { getSdkPackageVersion } from "./sdk-version.js";
|
|
6
|
-
export type { DevicePlaylistAssignment, DeviceRegistryRecord, PairedDeviceRecord, PendingCodeEntry, PendingCodeRecord, DeviceRegistryEntry, PlaylistItemRecord, PlaylistSchedule, PublishedPlaylistSnapshot, StoredPlaylist, TomorrowOSDataSnapshot, TomorrowOSMigratableStore, TomorrowOSStore } from "./store/types.js";
|
|
6
|
+
export type { DeviceOnOffTimer, DevicePlaylistAssignment, DeviceRegistryRecord, PairedDeviceRecord, PendingCodeEntry, PendingCodeRecord, DeviceRegistryEntry, PlaylistItemRecord, PlaylistSchedule, PublishedPlaylistSnapshot, StoredPlaylist, TomorrowOSDataSnapshot, TomorrowOSMigratableStore, TomorrowOSStore } from "./store/types.js";
|
|
7
7
|
export { PlaylistCatalog } from "./playlist-catalog.js";
|
|
8
8
|
export type { BuiltDevicePolicy, SavePlaylistInput } from "./playlist-catalog.js";
|
|
9
9
|
export { DEFAULT_PAIRING_CODE_SECRET, generateDeterministicPairingCode, generateRandomPairingCode, isValidPairingCodeFormat, normalizePairingCode, PAIRING_CODE_ALPHABET, PAIRING_CODE_LENGTH, resolvePairingCodeSecret } from "./pairing-code.js";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,YAAY,EACV,cAAc,EACd,oBAAoB,EACpB,aAAa,EACb,eAAe,EACf,iBAAiB,EAClB,MAAM,iBAAiB,CAAC;AACzB,YAAY,EACV,cAAc,EACd,eAAe,EACf,kBAAkB,EAClB,aAAa,EACd,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAExD,YAAY,EACV,wBAAwB,EACxB,oBAAoB,EACpB,kBAAkB,EAClB,gBAAgB,EAChB,iBAAiB,EACjB,mBAAmB,EACnB,kBAAkB,EAClB,gBAAgB,EAChB,yBAAyB,EACzB,cAAc,EACd,sBAAsB,EACtB,yBAAyB,EACzB,eAAe,EAChB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,YAAY,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAClF,OAAO,EACL,2BAA2B,EAC3B,gCAAgC,EAChC,yBAAyB,EACzB,wBAAwB,EACxB,oBAAoB,EACpB,qBAAqB,EACrB,mBAAmB,EACnB,wBAAwB,EACzB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,YAAY,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AACtE,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EACL,qBAAqB,EACrB,iBAAiB,EAClB,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EACV,4BAA4B,EAC5B,qBAAqB,EACtB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,oBAAoB,EACpB,oBAAoB,EACpB,qBAAqB,EACtB,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,YAAY,EACV,cAAc,EACd,oBAAoB,EACpB,aAAa,EACb,eAAe,EACf,iBAAiB,EAClB,MAAM,iBAAiB,CAAC;AACzB,YAAY,EACV,cAAc,EACd,eAAe,EACf,kBAAkB,EAClB,aAAa,EACd,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAExD,YAAY,EACV,gBAAgB,EAChB,wBAAwB,EACxB,oBAAoB,EACpB,kBAAkB,EAClB,gBAAgB,EAChB,iBAAiB,EACjB,mBAAmB,EACnB,kBAAkB,EAClB,gBAAgB,EAChB,yBAAyB,EACzB,cAAc,EACd,sBAAsB,EACtB,yBAAyB,EACzB,eAAe,EAChB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,YAAY,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAClF,OAAO,EACL,2BAA2B,EAC3B,gCAAgC,EAChC,yBAAyB,EACzB,wBAAwB,EACxB,oBAAoB,EACpB,qBAAqB,EACrB,mBAAmB,EACnB,wBAAwB,EACzB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,YAAY,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AACtE,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EACL,qBAAqB,EACrB,iBAAiB,EAClB,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EACV,4BAA4B,EAC5B,qBAAqB,EACtB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,oBAAoB,EACpB,oBAAoB,EACpB,qBAAqB,EACtB,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"postgres-store.d.ts","sourceRoot":"","sources":["../../src/store/postgres-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,KAAK,UAAU,EAAE,MAAM,IAAI,CAAC;AAE3C,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"postgres-store.d.ts","sourceRoot":"","sources":["../../src/store/postgres-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -125,6 +125,9 @@ export class PostgresStore {
|
|
|
125
125
|
ALTER TABLE paired_devices
|
|
126
126
|
ADD COLUMN IF NOT EXISTS last_screenshot_captured_at TEXT;
|
|
127
127
|
|
|
128
|
+
ALTER TABLE paired_devices
|
|
129
|
+
ADD COLUMN IF NOT EXISTS on_off_timer_json TEXT;
|
|
130
|
+
|
|
128
131
|
ALTER TABLE device_registry
|
|
129
132
|
ADD COLUMN IF NOT EXISTS display_name TEXT;
|
|
130
133
|
`);
|
|
@@ -363,9 +366,10 @@ export class PostgresStore {
|
|
|
363
366
|
last_offline_at,
|
|
364
367
|
last_policy_push_at,
|
|
365
368
|
last_screenshot_asset_id,
|
|
366
|
-
last_screenshot_captured_at
|
|
369
|
+
last_screenshot_captured_at,
|
|
370
|
+
on_off_timer_json
|
|
367
371
|
)
|
|
368
|
-
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14)
|
|
372
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15)
|
|
369
373
|
ON CONFLICT (device_id) DO UPDATE SET
|
|
370
374
|
pairing_token = EXCLUDED.pairing_token,
|
|
371
375
|
paired_at = EXCLUDED.paired_at,
|
|
@@ -379,7 +383,8 @@ export class PostgresStore {
|
|
|
379
383
|
last_offline_at = EXCLUDED.last_offline_at,
|
|
380
384
|
last_policy_push_at = EXCLUDED.last_policy_push_at,
|
|
381
385
|
last_screenshot_asset_id = EXCLUDED.last_screenshot_asset_id,
|
|
382
|
-
last_screenshot_captured_at = EXCLUDED.last_screenshot_captured_at
|
|
386
|
+
last_screenshot_captured_at = EXCLUDED.last_screenshot_captured_at,
|
|
387
|
+
on_off_timer_json = EXCLUDED.on_off_timer_json
|
|
383
388
|
`, [
|
|
384
389
|
deviceId,
|
|
385
390
|
record.pairingToken,
|
|
@@ -394,7 +399,8 @@ export class PostgresStore {
|
|
|
394
399
|
record.lastOfflineAt ?? null,
|
|
395
400
|
record.lastPolicyPushAt ?? null,
|
|
396
401
|
record.lastScreenshotAssetId ?? null,
|
|
397
|
-
record.lastScreenshotCapturedAt ?? null
|
|
402
|
+
record.lastScreenshotCapturedAt ?? null,
|
|
403
|
+
record.onOffTimer ? JSON.stringify(record.onOffTimer) : null
|
|
398
404
|
]);
|
|
399
405
|
}
|
|
400
406
|
async getPairedDevice(deviceId) {
|
|
@@ -626,6 +632,7 @@ export class PostgresStore {
|
|
|
626
632
|
};
|
|
627
633
|
}
|
|
628
634
|
mapPairedDeviceRow(row) {
|
|
635
|
+
const onOffTimer = parseJson(row.on_off_timer_json, null);
|
|
629
636
|
return {
|
|
630
637
|
pairingToken: row.pairing_token,
|
|
631
638
|
pairedAt: row.paired_at,
|
|
@@ -639,7 +646,8 @@ export class PostgresStore {
|
|
|
639
646
|
lastOfflineAt: optionalString(row.last_offline_at),
|
|
640
647
|
lastPolicyPushAt: optionalString(row.last_policy_push_at),
|
|
641
648
|
lastScreenshotAssetId: optionalString(row.last_screenshot_asset_id),
|
|
642
|
-
lastScreenshotCapturedAt: optionalString(row.last_screenshot_captured_at)
|
|
649
|
+
lastScreenshotCapturedAt: optionalString(row.last_screenshot_captured_at),
|
|
650
|
+
...(onOffTimer ? { onOffTimer } : {})
|
|
643
651
|
};
|
|
644
652
|
}
|
|
645
653
|
mapPlaylistRow(row) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sqlite-store.d.ts","sourceRoot":"","sources":["../../src/store/sqlite-store.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"sqlite-store.d.ts","sourceRoot":"","sources":["../../src/store/sqlite-store.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAEV,wBAAwB,EACxB,mBAAmB,EACnB,oBAAoB,EACpB,iBAAiB,EACjB,kBAAkB,EAClB,gBAAgB,EAChB,iBAAiB,EAGjB,cAAc,EACd,yBAAyB,EACzB,mBAAmB,EACpB,MAAM,YAAY,CAAC;AAGpB,UAAU,kBAAkB;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAgFD;;;GAGG;AACH,qBAAa,WAAY,YAAW,yBAAyB;IAC3D,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAoB;gBAE3B,OAAO,GAAE,kBAAkB,GAAG,MAAW;IAerD,IAAI,IAAI,IAAI;IAgGZ,OAAO,CAAC,uCAAuC;IAuF/C,OAAO,CAAC,cAAc;IAKtB,OAAO,CAAC,iCAAiC;IA4GzC,OAAO,CAAC,kBAAkB;IAS1B,KAAK,IAAI,IAAI;IAIP,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IAUtE,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,GAAG,SAAS,CAAC;IAUpE,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI9C,gBAAgB,IAAI,OAAO,CAAC,gBAAgB,EAAE,CAAC;IAY/C,iBAAiB,CACrB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,oBAAoB,GAAG,SAAS,CAAC;IAStC,iBAAiB,CACrB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,oBAAoB,GAC3B,OAAO,CAAC,IAAI,CAAC;IA8BV,uBAAuB,CAC3B,IAAI,EAAE,MAAM,GACX,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,oBAAoB,CAAA;KAAE,GAAG,SAAS,CAAC;IAapE,kBAAkB,IAAI,OAAO,CAAC,mBAAmB,EAAE,CAAC;IAYpD,eAAe,CACnB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,kBAAkB,GACzB,OAAO,CAAC,IAAI,CAAC;IAsDV,eAAe,CACnB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,kBAAkB,GAAG,SAAS,CAAC;IASpC,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAInD,iBAAiB,IAAI,OAAO,CAAC,iBAAiB,EAAE,CAAC;IAYjD,aAAa,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;IAS1C,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC;IAS5D,WAAW,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IA8BlD,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAcvE,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,GAAG,SAAS,CAAC;IAStE,wBAAwB,CAC5B,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,mBAAmB,GAAG,SAAS,CAAC;IAUrC,gBAAgB,CAAC,MAAM,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IAsC5D,mBAAmB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI9C,kBAAkB,IAAI,OAAO,CAAC,mBAAmB,EAAE,CAAC;IASpD,oBAAoB,CACxB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,wBAAwB,EAAE,CAAC;IAuBhC,oBAAoB,CACxB,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,wBAAwB,EAAE,GACtC,OAAO,CAAC,IAAI,CAAC;IA4BhB,OAAO,CAAC,oBAAoB;IAW5B,OAAO,CAAC,kBAAkB;IAuB1B,OAAO,CAAC,cAAc;IAYtB,OAAO,CAAC,mBAAmB;CAc5B"}
|
|
@@ -122,6 +122,7 @@ export class SQLiteStore {
|
|
|
122
122
|
this.addColumnIfMissing("paired_devices", "system_version TEXT");
|
|
123
123
|
this.addColumnIfMissing("paired_devices", "last_screenshot_asset_id TEXT");
|
|
124
124
|
this.addColumnIfMissing("paired_devices", "last_screenshot_captured_at TEXT");
|
|
125
|
+
this.addColumnIfMissing("paired_devices", "on_off_timer_json TEXT");
|
|
125
126
|
this.addColumnIfMissing("device_registry", "display_name TEXT");
|
|
126
127
|
this.migrateDropPlaylistVersionColumns();
|
|
127
128
|
this.migrateDropUploadedAssetStorageProvider();
|
|
@@ -413,9 +414,10 @@ export class SQLiteStore {
|
|
|
413
414
|
last_offline_at,
|
|
414
415
|
last_policy_push_at,
|
|
415
416
|
last_screenshot_asset_id,
|
|
416
|
-
last_screenshot_captured_at
|
|
417
|
+
last_screenshot_captured_at,
|
|
418
|
+
on_off_timer_json
|
|
417
419
|
)
|
|
418
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
420
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
419
421
|
ON CONFLICT(device_id) DO UPDATE SET
|
|
420
422
|
pairing_token = excluded.pairing_token,
|
|
421
423
|
paired_at = excluded.paired_at,
|
|
@@ -429,8 +431,9 @@ export class SQLiteStore {
|
|
|
429
431
|
last_offline_at = excluded.last_offline_at,
|
|
430
432
|
last_policy_push_at = excluded.last_policy_push_at,
|
|
431
433
|
last_screenshot_asset_id = excluded.last_screenshot_asset_id,
|
|
432
|
-
last_screenshot_captured_at = excluded.last_screenshot_captured_at
|
|
433
|
-
|
|
434
|
+
last_screenshot_captured_at = excluded.last_screenshot_captured_at,
|
|
435
|
+
on_off_timer_json = excluded.on_off_timer_json
|
|
436
|
+
`).run(deviceId, record.pairingToken, record.pairedAt, record.deviceName ?? null, record.platform ?? null, record.system ?? null, record.playerVersion ?? null, record.systemVersion ?? null, record.lastBootAt ?? null, record.lastOnlineAt ?? null, record.lastOfflineAt ?? null, record.lastPolicyPushAt ?? null, record.lastScreenshotAssetId ?? null, record.lastScreenshotCapturedAt ?? null, record.onOffTimer ? JSON.stringify(record.onOffTimer) : null);
|
|
434
437
|
}
|
|
435
438
|
async getPairedDevice(deviceId) {
|
|
436
439
|
const row = this.db.prepare(`
|
|
@@ -606,6 +609,7 @@ export class SQLiteStore {
|
|
|
606
609
|
};
|
|
607
610
|
}
|
|
608
611
|
mapPairedDeviceRow(row) {
|
|
612
|
+
const onOffTimer = parseJson(row.on_off_timer_json, null);
|
|
609
613
|
return {
|
|
610
614
|
pairingToken: row.pairing_token,
|
|
611
615
|
pairedAt: row.paired_at,
|
|
@@ -619,7 +623,8 @@ export class SQLiteStore {
|
|
|
619
623
|
lastOfflineAt: optionalString(row.last_offline_at),
|
|
620
624
|
lastPolicyPushAt: optionalString(row.last_policy_push_at),
|
|
621
625
|
lastScreenshotAssetId: optionalString(row.last_screenshot_asset_id),
|
|
622
|
-
lastScreenshotCapturedAt: optionalString(row.last_screenshot_captured_at)
|
|
626
|
+
lastScreenshotCapturedAt: optionalString(row.last_screenshot_captured_at),
|
|
627
|
+
...(onOffTimer ? { onOffTimer } : {})
|
|
623
628
|
};
|
|
624
629
|
}
|
|
625
630
|
mapPlaylistRow(row) {
|
package/dist/store/types.d.ts
CHANGED
|
@@ -16,6 +16,14 @@ export interface DeviceRegistryRecord {
|
|
|
16
16
|
/** CMS operator display name — survives unpair / re-pair. */
|
|
17
17
|
displayName?: string;
|
|
18
18
|
}
|
|
19
|
+
/** Device-local daily screen on/off window (HH:mm, device clock). Off = panel mute. */
|
|
20
|
+
export interface DeviceOnOffTimer {
|
|
21
|
+
enabled: boolean;
|
|
22
|
+
/** HH:mm — unmute / screen on */
|
|
23
|
+
turnOnAt: string;
|
|
24
|
+
/** HH:mm — panel mute / screen off (device stays CMS-connected) */
|
|
25
|
+
turnOffAt: string;
|
|
26
|
+
}
|
|
19
27
|
export interface PairedDeviceRecord {
|
|
20
28
|
pairingToken: string;
|
|
21
29
|
pairedAt: string;
|
|
@@ -31,6 +39,8 @@ export interface PairedDeviceRecord {
|
|
|
31
39
|
/** Latest device screenshot stored via uploaded_assets (local or Cloudinary). */
|
|
32
40
|
lastScreenshotAssetId?: string;
|
|
33
41
|
lastScreenshotCapturedAt?: string;
|
|
42
|
+
/** Tizen screen mute schedule (panel mute; not power off). */
|
|
43
|
+
onOffTimer?: DeviceOnOffTimer;
|
|
34
44
|
}
|
|
35
45
|
export interface PairedDeviceEntry {
|
|
36
46
|
deviceId: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/store/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,wFAAwF;AACxF,MAAM,WAAW,oBAAoB;IACnC,oBAAoB,EAAE,MAAM,CAAC;IAC7B,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,6DAA6D;IAC7D,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,kBAAkB;IACjC,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,iFAAiF;IACjF,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,wBAAwB,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/store/types.ts"],"names":[],"mappings":"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"}
|
package/dist/tomorrowos.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { EventEmitter } from "events";
|
|
2
2
|
import http from "http";
|
|
3
3
|
import { PlaylistCatalog, type BuiltDevicePolicy } from "./playlist-catalog.js";
|
|
4
|
-
import type { TomorrowOSStore } from "./store/types.js";
|
|
4
|
+
import type { DeviceOnOffTimer, TomorrowOSStore } from "./store/types.js";
|
|
5
5
|
export type { ConnectorState, ConnectorStatus, ServerStatusReport, StatusBlocker } from "./server-status.js";
|
|
6
6
|
export interface TomorrowOSBrand {
|
|
7
7
|
name?: string;
|
|
@@ -66,6 +66,8 @@ export interface DeviceListItem {
|
|
|
66
66
|
url: string;
|
|
67
67
|
capturedAt: string;
|
|
68
68
|
} | null;
|
|
69
|
+
/** Tizen daily screen mute schedule (panel mute; device stays connected). */
|
|
70
|
+
onOffTimer: DeviceOnOffTimer | null;
|
|
69
71
|
}
|
|
70
72
|
export interface DeviceLogEntry {
|
|
71
73
|
timestamp: string;
|
|
@@ -123,6 +125,16 @@ export declare class TomorrowOS extends EventEmitter {
|
|
|
123
125
|
};
|
|
124
126
|
/** List paired devices with live connection + timing fields for the CMS panel. */
|
|
125
127
|
listDevices(): Promise<DeviceListItem[]>;
|
|
128
|
+
/**
|
|
129
|
+
* Persist a daily on/off timer (Tizen panel mute). Saved even if offline;
|
|
130
|
+
* pushed to the player when connected.
|
|
131
|
+
*/
|
|
132
|
+
setDeviceOnOffTimer(deviceId: string, timerInput: unknown): Promise<{
|
|
133
|
+
deviceId: string;
|
|
134
|
+
onOffTimer: DeviceOnOffTimer;
|
|
135
|
+
pushed: boolean;
|
|
136
|
+
}>;
|
|
137
|
+
private pushOnOffTimerToDevice;
|
|
126
138
|
setDeviceName(deviceId: string, deviceName: string): Promise<{
|
|
127
139
|
deviceId: string;
|
|
128
140
|
deviceName: string;
|
package/dist/tomorrowos.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tomorrowos.d.ts","sourceRoot":"","sources":["../src/tomorrowos.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAEtC,OAAO,IAAI,MAAM,MAAM,CAAC;AAYxB,OAAO,EAAE,eAAe,EAAE,KAAK,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAChF,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"tomorrowos.d.ts","sourceRoot":"","sources":["../src/tomorrowos.ts"],"names":[],"mappings":"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"}
|
package/dist/tomorrowos.js
CHANGED
|
@@ -45,6 +45,23 @@ function normalizeDeviceSystemLabel(platform, system) {
|
|
|
45
45
|
const label = typeof system === "string" ? system.trim() : "";
|
|
46
46
|
return label || undefined;
|
|
47
47
|
}
|
|
48
|
+
const ON_OFF_TIME_RE = /^([01]\d|2[0-3]):[0-5]\d$/;
|
|
49
|
+
function normalizeOnOffTimer(input) {
|
|
50
|
+
if (!input || typeof input !== "object") {
|
|
51
|
+
throw new Error("onOffTimer object is required");
|
|
52
|
+
}
|
|
53
|
+
const body = input;
|
|
54
|
+
const enabled = Boolean(body.enabled);
|
|
55
|
+
const turnOnAt = String(body.turnOnAt ?? "").trim();
|
|
56
|
+
const turnOffAt = String(body.turnOffAt ?? "").trim();
|
|
57
|
+
if (!ON_OFF_TIME_RE.test(turnOnAt) || !ON_OFF_TIME_RE.test(turnOffAt)) {
|
|
58
|
+
throw new Error("turnOnAt and turnOffAt must be HH:mm (24h)");
|
|
59
|
+
}
|
|
60
|
+
if (turnOnAt === turnOffAt) {
|
|
61
|
+
throw new Error("turnOnAt and turnOffAt must be different");
|
|
62
|
+
}
|
|
63
|
+
return { enabled, turnOnAt, turnOffAt };
|
|
64
|
+
}
|
|
48
65
|
function isRemoteUploadedAssetUrl(url) {
|
|
49
66
|
return /^https?:\/\//i.test(String(url || "").trim());
|
|
50
67
|
}
|
|
@@ -284,6 +301,9 @@ export class TomorrowOS extends EventEmitter {
|
|
|
284
301
|
void this.pushLatestPolicyToDevice(deviceId).catch((err) => {
|
|
285
302
|
console.error("[TomorrowOS] pushLatestPolicy on paired failed:", err);
|
|
286
303
|
});
|
|
304
|
+
void this.pushOnOffTimerToDevice(deviceId).catch((err) => {
|
|
305
|
+
console.error("[TomorrowOS] pushOnOffTimer on paired failed:", err);
|
|
306
|
+
});
|
|
287
307
|
}
|
|
288
308
|
this.emit("device.paired", { deviceId });
|
|
289
309
|
return { deviceId };
|
|
@@ -384,10 +404,48 @@ export class TomorrowOS extends EventEmitter {
|
|
|
384
404
|
screenOnlineSince,
|
|
385
405
|
latestErrorAt: latestError?.timestamp ?? null,
|
|
386
406
|
latestErrorMessage: latestError?.message ?? null,
|
|
387
|
-
latestScreenshot
|
|
407
|
+
latestScreenshot,
|
|
408
|
+
onOffTimer: record.onOffTimer ?? null
|
|
388
409
|
};
|
|
389
410
|
}));
|
|
390
411
|
}
|
|
412
|
+
/**
|
|
413
|
+
* Persist a daily on/off timer (Tizen panel mute). Saved even if offline;
|
|
414
|
+
* pushed to the player when connected.
|
|
415
|
+
*/
|
|
416
|
+
async setDeviceOnOffTimer(deviceId, timerInput) {
|
|
417
|
+
const id = String(deviceId || "").trim();
|
|
418
|
+
if (!id) {
|
|
419
|
+
throw new Error("deviceId is required");
|
|
420
|
+
}
|
|
421
|
+
const existing = await this.store.getPairedDevice(id);
|
|
422
|
+
if (!existing) {
|
|
423
|
+
throw new Error("Device is not paired");
|
|
424
|
+
}
|
|
425
|
+
const onOffTimer = normalizeOnOffTimer(timerInput);
|
|
426
|
+
await this.store.setPairedDevice(id, {
|
|
427
|
+
...existing,
|
|
428
|
+
onOffTimer
|
|
429
|
+
});
|
|
430
|
+
const pushed = await this.pushOnOffTimerToDevice(id);
|
|
431
|
+
return { deviceId: id, onOffTimer, pushed };
|
|
432
|
+
}
|
|
433
|
+
async pushOnOffTimerToDevice(deviceId) {
|
|
434
|
+
const existing = await this.store.getPairedDevice(deviceId);
|
|
435
|
+
if (!existing?.onOffTimer)
|
|
436
|
+
return false;
|
|
437
|
+
const ws = this.devices.get(deviceId);
|
|
438
|
+
if (!ws || ws.readyState !== WebSocket.OPEN)
|
|
439
|
+
return false;
|
|
440
|
+
try {
|
|
441
|
+
const result = await this.sendCommandToSocket(ws, deviceId, "device.display.setOnOffTimer", { onOffTimer: existing.onOffTimer }, 15_000);
|
|
442
|
+
return result.status === "success" || result.status === "accepted";
|
|
443
|
+
}
|
|
444
|
+
catch (err) {
|
|
445
|
+
console.error("[TomorrowOS] pushOnOffTimer failed:", err);
|
|
446
|
+
return false;
|
|
447
|
+
}
|
|
448
|
+
}
|
|
391
449
|
async setDeviceName(deviceId, deviceName) {
|
|
392
450
|
const id = String(deviceId || "").trim();
|
|
393
451
|
if (!id) {
|
|
@@ -1091,6 +1149,20 @@ export class TomorrowOS extends EventEmitter {
|
|
|
1091
1149
|
}
|
|
1092
1150
|
return;
|
|
1093
1151
|
}
|
|
1152
|
+
const deviceOnOffTimer = /^\/device\/([^/]+)\/on-off-timer$/.exec(pathname);
|
|
1153
|
+
if (req.method === "POST" && deviceOnOffTimer) {
|
|
1154
|
+
const deviceId = decodeURIComponent(deviceOnOffTimer[1]);
|
|
1155
|
+
const body = (await readJsonBody(req));
|
|
1156
|
+
try {
|
|
1157
|
+
const result = await this.setDeviceOnOffTimer(deviceId, body.onOffTimer ?? body);
|
|
1158
|
+
sendJson(res, 200, { status: "success", ...result });
|
|
1159
|
+
}
|
|
1160
|
+
catch (e) {
|
|
1161
|
+
const msg = e instanceof Error ? e.message : "On/off timer failed";
|
|
1162
|
+
sendJson(res, 400, { status: "failed", error: msg });
|
|
1163
|
+
}
|
|
1164
|
+
return;
|
|
1165
|
+
}
|
|
1094
1166
|
if (req.method === "GET" && pathname === "/playlists") {
|
|
1095
1167
|
const playlists = await this.playlists.listPlaylists();
|
|
1096
1168
|
sendJson(res, 200, { status: "success", playlists });
|
|
@@ -1477,6 +1549,9 @@ export class TomorrowOS extends EventEmitter {
|
|
|
1477
1549
|
void this.pushLatestPolicyToDevice(deviceId).catch((err) => {
|
|
1478
1550
|
console.error("[TomorrowOS] pushLatestPolicy on resume failed:", err);
|
|
1479
1551
|
});
|
|
1552
|
+
void this.pushOnOffTimerToDevice(deviceId).catch((err) => {
|
|
1553
|
+
console.error("[TomorrowOS] pushOnOffTimer on resume failed:", err);
|
|
1554
|
+
});
|
|
1480
1555
|
})();
|
|
1481
1556
|
return;
|
|
1482
1557
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tomorrowos/sdk",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.13",
|
|
4
4
|
"description": "TomorrowOS CMS server SDK - WebSocket transport, pairing, device commands, optional static CMS UI. Includes CLI (tomorrowos init / build) and starter templates.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "my-cms",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.13",
|
|
4
4
|
"description": "CMS server on @tomorrowos/sdk. Add your UI (React, static files, etc.) alongside this server.",
|
|
5
5
|
"private": true,
|
|
6
6
|
"type": "module",
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"build-player": "tomorrowos build --platform tizen"
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"@tomorrowos/sdk": "^0.9.
|
|
16
|
+
"@tomorrowos/sdk": "^0.9.13",
|
|
17
17
|
"dotenv": "^17.2.3",
|
|
18
18
|
"tsx": "^4.19.0"
|
|
19
19
|
},
|
|
@@ -180,6 +180,35 @@
|
|
|
180
180
|
</div>
|
|
181
181
|
</div>
|
|
182
182
|
|
|
183
|
+
<div id="onOffTimerModal" class="modal hidden" role="dialog" aria-modal="true">
|
|
184
|
+
<div class="modal-backdrop" data-close-on-off-timer-modal="1"></div>
|
|
185
|
+
<div class="modal-card">
|
|
186
|
+
<h2>On / off timer</h2>
|
|
187
|
+
<p class="hint" id="onOffTimerModalHint">
|
|
188
|
+
Daily schedule on the device clock. Off uses Samsung panel mute (screen black); the player stays connected to the CMS.
|
|
189
|
+
</p>
|
|
190
|
+
<label class="field-label on-off-timer-enable">
|
|
191
|
+
<input type="checkbox" id="onOffTimerEnabled" />
|
|
192
|
+
Enable daily timer
|
|
193
|
+
</label>
|
|
194
|
+
<div class="on-off-timer-grid">
|
|
195
|
+
<label class="field-label">
|
|
196
|
+
Turn on (unmute)
|
|
197
|
+
<input type="time" id="onOffTimerTurnOnAt" value="06:00" />
|
|
198
|
+
</label>
|
|
199
|
+
<label class="field-label">
|
|
200
|
+
Turn off (mute)
|
|
201
|
+
<input type="time" id="onOffTimerTurnOffAt" value="18:00" />
|
|
202
|
+
</label>
|
|
203
|
+
</div>
|
|
204
|
+
<p class="hint" id="onOffTimerModalStatus"></p>
|
|
205
|
+
<div class="modal-actions">
|
|
206
|
+
<button type="button" id="onOffTimerSaveBtn" class="primary">Save</button>
|
|
207
|
+
<button type="button" data-close-on-off-timer-modal="1">Cancel</button>
|
|
208
|
+
</div>
|
|
209
|
+
</div>
|
|
210
|
+
</div>
|
|
211
|
+
|
|
183
212
|
<div id="downloadFailedModal" class="modal hidden" role="dialog" aria-modal="true">
|
|
184
213
|
<div class="modal-backdrop" data-close-download-failed-modal="1"></div>
|
|
185
214
|
<div class="modal-card">
|
|
@@ -1207,7 +1207,6 @@ function renderDeviceCards() {
|
|
|
1207
1207
|
const primaryRows = [
|
|
1208
1208
|
["Device ID", device.deviceId],
|
|
1209
1209
|
["System", device.system || device.platform || "—"],
|
|
1210
|
-
["System version", device.systemVersion || "—"],
|
|
1211
1210
|
["Player version", device.playerVersion || "—"]
|
|
1212
1211
|
];
|
|
1213
1212
|
for (const [label, value] of primaryRows) {
|
|
@@ -1279,6 +1278,12 @@ function renderDeviceCards() {
|
|
|
1279
1278
|
latestScreenshotBtn.textContent = "Last screen";
|
|
1280
1279
|
latestScreenshotBtn.addEventListener("click", () => viewLatestScreenshot(device.deviceId));
|
|
1281
1280
|
|
|
1281
|
+
const timerBtn = document.createElement("button");
|
|
1282
|
+
timerBtn.type = "button";
|
|
1283
|
+
timerBtn.textContent = device.onOffTimer?.enabled ? "Timer · On" : "Timer";
|
|
1284
|
+
timerBtn.title = "Daily screen on/off (Tizen panel mute)";
|
|
1285
|
+
timerBtn.addEventListener("click", () => openOnOffTimerModal(device.deviceId));
|
|
1286
|
+
|
|
1282
1287
|
const unpairBtn = document.createElement("button");
|
|
1283
1288
|
unpairBtn.type = "button";
|
|
1284
1289
|
unpairBtn.className = "danger";
|
|
@@ -1293,6 +1298,9 @@ function renderDeviceCards() {
|
|
|
1293
1298
|
actions.appendChild(logsBtn);
|
|
1294
1299
|
actions.appendChild(screenshotBtn);
|
|
1295
1300
|
actions.appendChild(latestScreenshotBtn);
|
|
1301
|
+
if (isTizenDevice(device)) {
|
|
1302
|
+
actions.appendChild(timerBtn);
|
|
1303
|
+
}
|
|
1296
1304
|
actions.appendChild(unpairBtn);
|
|
1297
1305
|
|
|
1298
1306
|
card.appendChild(header);
|
|
@@ -1785,6 +1793,106 @@ function closeScreenshotModal() {
|
|
|
1785
1793
|
modal?.classList.add("hidden");
|
|
1786
1794
|
}
|
|
1787
1795
|
|
|
1796
|
+
function isTizenDevice(device) {
|
|
1797
|
+
const platform = String(device?.platform || "").toLowerCase();
|
|
1798
|
+
const system = String(device?.system || "").toLowerCase();
|
|
1799
|
+
return platform.includes("tizen") || system.includes("tizen");
|
|
1800
|
+
}
|
|
1801
|
+
|
|
1802
|
+
function normalizeTimeInputValue(value, fallback) {
|
|
1803
|
+
const raw = String(value || "").trim();
|
|
1804
|
+
const match = /^(\d{1,2}):(\d{2})/.exec(raw);
|
|
1805
|
+
if (!match) return fallback;
|
|
1806
|
+
const hh = Math.min(23, Math.max(0, Number(match[1])));
|
|
1807
|
+
const mm = Math.min(59, Math.max(0, Number(match[2])));
|
|
1808
|
+
if (Number.isNaN(hh) || Number.isNaN(mm)) return fallback;
|
|
1809
|
+
return `${String(hh).padStart(2, "0")}:${String(mm).padStart(2, "0")}`;
|
|
1810
|
+
}
|
|
1811
|
+
|
|
1812
|
+
let onOffTimerModalDeviceId = null;
|
|
1813
|
+
|
|
1814
|
+
function openOnOffTimerModal(deviceId) {
|
|
1815
|
+
const device = devicesCache.find((d) => d.deviceId === deviceId);
|
|
1816
|
+
if (!device) return;
|
|
1817
|
+
if (!isTizenDevice(device)) {
|
|
1818
|
+
alert("On/off timer is available for Samsung Tizen players only.");
|
|
1819
|
+
return;
|
|
1820
|
+
}
|
|
1821
|
+
|
|
1822
|
+
onOffTimerModalDeviceId = deviceId;
|
|
1823
|
+
const modal = document.getElementById("onOffTimerModal");
|
|
1824
|
+
const hint = document.getElementById("onOffTimerModalHint");
|
|
1825
|
+
const status = document.getElementById("onOffTimerModalStatus");
|
|
1826
|
+
const enabledEl = document.getElementById("onOffTimerEnabled");
|
|
1827
|
+
const onEl = document.getElementById("onOffTimerTurnOnAt");
|
|
1828
|
+
const offEl = document.getElementById("onOffTimerTurnOffAt");
|
|
1829
|
+
if (!modal || !enabledEl || !onEl || !offEl) return;
|
|
1830
|
+
|
|
1831
|
+
const timer = device.onOffTimer || {};
|
|
1832
|
+
enabledEl.checked = Boolean(timer.enabled);
|
|
1833
|
+
onEl.value = normalizeTimeInputValue(timer.turnOnAt, "06:00");
|
|
1834
|
+
offEl.value = normalizeTimeInputValue(timer.turnOffAt, "18:00");
|
|
1835
|
+
if (hint) {
|
|
1836
|
+
hint.textContent =
|
|
1837
|
+
"Daily schedule on the device clock. Off uses Samsung panel mute (screen black); the player stays connected to the CMS.";
|
|
1838
|
+
}
|
|
1839
|
+
if (status) {
|
|
1840
|
+
status.textContent = device.connected
|
|
1841
|
+
? "Device is online — save will apply immediately."
|
|
1842
|
+
: "Device is offline — schedule will save and apply when it reconnects.";
|
|
1843
|
+
}
|
|
1844
|
+
modal.classList.remove("hidden");
|
|
1845
|
+
}
|
|
1846
|
+
|
|
1847
|
+
function closeOnOffTimerModal() {
|
|
1848
|
+
const modal = document.getElementById("onOffTimerModal");
|
|
1849
|
+
if (modal) modal.classList.add("hidden");
|
|
1850
|
+
onOffTimerModalDeviceId = null;
|
|
1851
|
+
}
|
|
1852
|
+
|
|
1853
|
+
async function saveOnOffTimerModal() {
|
|
1854
|
+
const deviceId = onOffTimerModalDeviceId;
|
|
1855
|
+
if (!deviceId) return;
|
|
1856
|
+
|
|
1857
|
+
const enabledEl = document.getElementById("onOffTimerEnabled");
|
|
1858
|
+
const onEl = document.getElementById("onOffTimerTurnOnAt");
|
|
1859
|
+
const offEl = document.getElementById("onOffTimerTurnOffAt");
|
|
1860
|
+
const saveBtn = document.getElementById("onOffTimerSaveBtn");
|
|
1861
|
+
if (!enabledEl || !onEl || !offEl) return;
|
|
1862
|
+
|
|
1863
|
+
const onOffTimer = {
|
|
1864
|
+
enabled: Boolean(enabledEl.checked),
|
|
1865
|
+
turnOnAt: normalizeTimeInputValue(onEl.value, "06:00"),
|
|
1866
|
+
turnOffAt: normalizeTimeInputValue(offEl.value, "18:00")
|
|
1867
|
+
};
|
|
1868
|
+
|
|
1869
|
+
if (onOffTimer.turnOnAt === onOffTimer.turnOffAt) {
|
|
1870
|
+
alert("Turn on and turn off times must be different.");
|
|
1871
|
+
return;
|
|
1872
|
+
}
|
|
1873
|
+
|
|
1874
|
+
if (saveBtn) saveBtn.disabled = true;
|
|
1875
|
+
try {
|
|
1876
|
+
const res = await fetch(`/device/${encodeURIComponent(deviceId)}/on-off-timer`, {
|
|
1877
|
+
method: "POST",
|
|
1878
|
+
headers: { "Content-Type": "application/json" },
|
|
1879
|
+
body: JSON.stringify({ onOffTimer })
|
|
1880
|
+
});
|
|
1881
|
+
const data = await res.json();
|
|
1882
|
+
if (!res.ok || data.status === "failed") {
|
|
1883
|
+
alert(data.error || "Could not save on/off timer");
|
|
1884
|
+
return;
|
|
1885
|
+
}
|
|
1886
|
+
showResult({ deviceId, onOffTimer: data.onOffTimer, pushed: data.pushed });
|
|
1887
|
+
closeOnOffTimerModal();
|
|
1888
|
+
await fetchDevices();
|
|
1889
|
+
} catch (err) {
|
|
1890
|
+
alert(err?.message || "Could not save on/off timer");
|
|
1891
|
+
} finally {
|
|
1892
|
+
if (saveBtn) saveBtn.disabled = false;
|
|
1893
|
+
}
|
|
1894
|
+
}
|
|
1895
|
+
|
|
1788
1896
|
function openDownloadFailedModal(detail) {
|
|
1789
1897
|
const modal = document.getElementById("downloadFailedModal");
|
|
1790
1898
|
const message = document.getElementById("downloadFailedModalMessage");
|
|
@@ -2101,6 +2209,12 @@ document.addEventListener("DOMContentLoaded", () => {
|
|
|
2101
2209
|
document.querySelectorAll("[data-close-screenshot-modal]").forEach((el) => {
|
|
2102
2210
|
el.addEventListener("click", closeScreenshotModal);
|
|
2103
2211
|
});
|
|
2212
|
+
document.querySelectorAll("[data-close-on-off-timer-modal]").forEach((el) => {
|
|
2213
|
+
el.addEventListener("click", closeOnOffTimerModal);
|
|
2214
|
+
});
|
|
2215
|
+
document
|
|
2216
|
+
.getElementById("onOffTimerSaveBtn")
|
|
2217
|
+
?.addEventListener("click", () => void saveOnOffTimerModal());
|
|
2104
2218
|
document.querySelectorAll("[data-close-download-failed-modal]").forEach((el) => {
|
|
2105
2219
|
el.addEventListener("click", closeDownloadFailedModal);
|
|
2106
2220
|
});
|
|
@@ -829,6 +829,30 @@ button.danger {
|
|
|
829
829
|
width: min(94vw, 860px);
|
|
830
830
|
}
|
|
831
831
|
|
|
832
|
+
.on-off-timer-enable {
|
|
833
|
+
display: flex;
|
|
834
|
+
align-items: center;
|
|
835
|
+
gap: 0.5rem;
|
|
836
|
+
margin: 0.85rem 0 0.65rem;
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
.on-off-timer-enable input {
|
|
840
|
+
width: auto;
|
|
841
|
+
margin: 0;
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
.on-off-timer-grid {
|
|
845
|
+
display: grid;
|
|
846
|
+
grid-template-columns: 1fr 1fr;
|
|
847
|
+
gap: 0.75rem;
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
@media (max-width: 520px) {
|
|
851
|
+
.on-off-timer-grid {
|
|
852
|
+
grid-template-columns: 1fr;
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
|
|
832
856
|
.screenshot-preview {
|
|
833
857
|
display: block;
|
|
834
858
|
width: 100%;
|