@tomorrowos/sdk 0.3.3 → 0.3.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/playlist-catalog.d.ts +0 -3
- package/dist/playlist-catalog.d.ts.map +1 -1
- package/dist/playlist-catalog.js +19 -13
- package/package.json +1 -1
- package/templates/cms-starter/package.json +2 -2
- package/templates/cms-starter/public/index.html +5 -2
- package/templates/cms-starter/public/methods.js +17 -6
|
@@ -13,13 +13,10 @@ export interface BuiltDevicePolicy {
|
|
|
13
13
|
};
|
|
14
14
|
revision?: number;
|
|
15
15
|
syncMode?: "latest" | "snapshot";
|
|
16
|
-
/** One-shot: player may start outside schedule right after publish. */
|
|
17
|
-
playNow?: boolean;
|
|
18
16
|
};
|
|
19
17
|
}
|
|
20
18
|
export interface PolicyBuildOptions {
|
|
21
19
|
useLatest?: boolean;
|
|
22
|
-
playNow?: boolean;
|
|
23
20
|
mediaBaseUrl?: string;
|
|
24
21
|
}
|
|
25
22
|
export declare class PlaylistCatalog {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"playlist-catalog.d.ts","sourceRoot":"","sources":["../src/playlist-catalog.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,wBAAwB,EACxB,kBAAkB,EAClB,gBAAgB,EAChB,yBAAyB,EACzB,cAAc,EACd,eAAe,EAChB,MAAM,kBAAkB,CAAC;AAE1B,MAAM,WAAW,iBAAiB;IAChC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,gBAAgB,CAAC;IAC5B,KAAK,EAAE,kBAAkB,EAAE,CAAC;CAC7B;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE;QACN,SAAS,EAAE,yBAAyB,EAAE,CAAC;QACvC,QAAQ,EAAE;YAAE,IAAI,EAAE,OAAO,CAAA;SAAE,CAAC;QAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,QAAQ,CAAC,EAAE,QAAQ,GAAG,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"playlist-catalog.d.ts","sourceRoot":"","sources":["../src/playlist-catalog.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,wBAAwB,EACxB,kBAAkB,EAClB,gBAAgB,EAChB,yBAAyB,EACzB,cAAc,EACd,eAAe,EAChB,MAAM,kBAAkB,CAAC;AAE1B,MAAM,WAAW,iBAAiB;IAChC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,gBAAgB,CAAC;IAC5B,KAAK,EAAE,kBAAkB,EAAE,CAAC;CAC7B;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE;QACN,SAAS,EAAE,yBAAyB,EAAE,CAAC;QACvC,QAAQ,EAAE;YAAE,IAAI,EAAE,OAAO,CAAA;SAAE,CAAC;QAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,QAAQ,CAAC,EAAE,QAAQ,GAAG,UAAU,CAAC;KAClC,CAAC;CACH;AAED,MAAM,WAAW,kBAAkB;IACjC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AA+CD,qBAAa,eAAe;IACd,OAAO,CAAC,QAAQ,CAAC,KAAK;gBAAL,KAAK,EAAE,eAAe;IAE7C,aAAa,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;IAK1C,6BAA6B,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;IAI1D,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC;IAI5D,YAAY,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,cAAc,CAAC;IAgC/D,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAcnD,oBAAoB,CACxB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,wBAAwB,EAAE,CAAC;IAIhC,wBAAwB,CAC5B,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EAAE,EACrB,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,iBAAiB,CAAC;IA2CvB,wBAAwB,CAC5B,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,iBAAiB,CAAC;IAOvB,oBAAoB,CACxB,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,iBAAiB,CAAC;YAKf,0BAA0B;IAgCxC,6BAA6B,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAGpE"}
|
package/dist/playlist-catalog.js
CHANGED
|
@@ -101,14 +101,23 @@ export class PlaylistCatalog {
|
|
|
101
101
|
return this.store.getDeviceAssignments(deviceId);
|
|
102
102
|
}
|
|
103
103
|
async publishPlaylistsToDevice(deviceId, playlistIds, options = {}) {
|
|
104
|
-
const
|
|
105
|
-
if (
|
|
104
|
+
const incoming = [...new Set(playlistIds.map((x) => String(x).trim()).filter(Boolean))];
|
|
105
|
+
if (incoming.length === 0) {
|
|
106
106
|
throw Object.assign(new Error("Select at least one playlist"), {
|
|
107
107
|
code: "PLAYLIST_INVALID"
|
|
108
108
|
});
|
|
109
109
|
}
|
|
110
|
+
const existing = await this.store.getDeviceAssignments(deviceId);
|
|
111
|
+
const existingById = new Map(existing.map((a) => [a.playlistId, a]));
|
|
112
|
+
const allIds = [...new Set([...existing.map((a) => a.playlistId), ...incoming])];
|
|
110
113
|
const assignments = [];
|
|
111
|
-
for (const playlistId of
|
|
114
|
+
for (const playlistId of allIds) {
|
|
115
|
+
if (!incoming.includes(playlistId)) {
|
|
116
|
+
const kept = existingById.get(playlistId);
|
|
117
|
+
if (kept)
|
|
118
|
+
assignments.push(kept);
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
112
121
|
const playlist = await this.store.getPlaylist(playlistId);
|
|
113
122
|
if (!playlist || playlist.retired) {
|
|
114
123
|
throw Object.assign(new Error(`Playlist not available: ${playlistId}`), {
|
|
@@ -125,7 +134,6 @@ export class PlaylistCatalog {
|
|
|
125
134
|
await this.store.setDeviceAssignments(deviceId, assignments);
|
|
126
135
|
return this.buildPolicyFromAssignments(assignments, {
|
|
127
136
|
useLatest: false,
|
|
128
|
-
playNow: true,
|
|
129
137
|
mediaBaseUrl: options.mediaBaseUrl
|
|
130
138
|
});
|
|
131
139
|
}
|
|
@@ -156,16 +164,14 @@ export class PlaylistCatalog {
|
|
|
156
164
|
items: absolutizePlaylistItems(assignment.snapshot.items, mediaBaseUrl)
|
|
157
165
|
});
|
|
158
166
|
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
167
|
+
return {
|
|
168
|
+
policy: {
|
|
169
|
+
playlists,
|
|
170
|
+
fallback: { type: "brand" },
|
|
171
|
+
revision: Date.now(),
|
|
172
|
+
syncMode: useLatest ? "latest" : "snapshot"
|
|
173
|
+
}
|
|
164
174
|
};
|
|
165
|
-
if (options.playNow === true) {
|
|
166
|
-
policy.playNow = true;
|
|
167
|
-
}
|
|
168
|
-
return { policy };
|
|
169
175
|
}
|
|
170
176
|
canPublishPlaylistToNewDevice(playlistId) {
|
|
171
177
|
return this.store.getPlaylist(playlistId).then((p) => !!p && !p?.retired);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tomorrowos/sdk",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.4",
|
|
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.3.
|
|
3
|
+
"version": "0.3.4",
|
|
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",
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"build-player": "tomorrowos build --platform tizen"
|
|
11
11
|
},
|
|
12
12
|
"dependencies": {
|
|
13
|
-
"@tomorrowos/sdk": "^0.3.
|
|
13
|
+
"@tomorrowos/sdk": "^0.3.4"
|
|
14
14
|
},
|
|
15
15
|
"devDependencies": {
|
|
16
16
|
"@types/node": "^20.0.0",
|
|
@@ -64,7 +64,10 @@
|
|
|
64
64
|
</label>
|
|
65
65
|
|
|
66
66
|
<h3 class="subheading">When this playlist plays</h3>
|
|
67
|
-
<p class="hint">
|
|
67
|
+
<p class="hint">
|
|
68
|
+
Leave blank for always on. Uses the <strong>TV/device local clock</strong> (not CMS server time).
|
|
69
|
+
“Until” includes that minute (e.g. Until 18:00 plays through 18:00).
|
|
70
|
+
</p>
|
|
68
71
|
<div class="schedule-grid">
|
|
69
72
|
<label>
|
|
70
73
|
Start date
|
|
@@ -124,7 +127,7 @@
|
|
|
124
127
|
<div class="modal-backdrop" data-close-modal="1"></div>
|
|
125
128
|
<div class="modal-card">
|
|
126
129
|
<h2>Publish to device</h2>
|
|
127
|
-
<p class="hint" id="publishModalHint">Select playlists to
|
|
130
|
+
<p class="hint" id="publishModalHint">Select playlists to add to this device. Already-published playlists are not listed here.</p>
|
|
128
131
|
<div id="publishChecklist" class="publish-checklist"></div>
|
|
129
132
|
<div class="modal-actions">
|
|
130
133
|
<button type="button" id="publishConfirmBtn" class="primary">Publish selected</button>
|
|
@@ -217,7 +217,7 @@ async function fetchPlaylists() {
|
|
|
217
217
|
showResult({
|
|
218
218
|
status: "failed",
|
|
219
219
|
error:
|
|
220
|
-
"CMS server is missing /playlists. Restart CMS with @tomorrowos/sdk 0.3.
|
|
220
|
+
"CMS server is missing /playlists. Restart CMS with @tomorrowos/sdk 0.3.4 or newer."
|
|
221
221
|
});
|
|
222
222
|
}
|
|
223
223
|
return;
|
|
@@ -626,17 +626,24 @@ function openPublishModal(deviceId) {
|
|
|
626
626
|
return;
|
|
627
627
|
}
|
|
628
628
|
|
|
629
|
-
|
|
629
|
+
const pubs = devicesCache.find((d) => d.deviceId === deviceId)?.publishedPlaylists || [];
|
|
630
|
+
const publishedIds = new Set(pubs.map((p) => p.playlistId));
|
|
631
|
+
const unpublished = playlistsCatalog.filter((pl) => !publishedIds.has(pl.id));
|
|
632
|
+
|
|
633
|
+
if (unpublished.length === 0) {
|
|
634
|
+
alert("All playlists are already published to this device. Use Remove on the card to unpublish one first.");
|
|
635
|
+
return;
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
hint.textContent = `Device ${deviceId} — add playlists not yet on this device (snapshot at publish time).`;
|
|
630
639
|
checklist.innerHTML = "";
|
|
631
640
|
|
|
632
|
-
for (const pl of
|
|
641
|
+
for (const pl of unpublished) {
|
|
633
642
|
const label = document.createElement("label");
|
|
634
643
|
const cb = document.createElement("input");
|
|
635
644
|
cb.type = "checkbox";
|
|
636
645
|
cb.value = pl.id;
|
|
637
646
|
cb.dataset.name = pl.name;
|
|
638
|
-
const pubs = devicesCache.find((d) => d.deviceId === deviceId)?.publishedPlaylists || [];
|
|
639
|
-
if (pubs.some((p) => p.playlistId === pl.id)) cb.checked = true;
|
|
640
647
|
label.appendChild(cb);
|
|
641
648
|
label.appendChild(document.createTextNode(` ${pl.name} (v${pl.version})`));
|
|
642
649
|
checklist.appendChild(label);
|
|
@@ -680,7 +687,11 @@ async function confirmPublishModal() {
|
|
|
680
687
|
return;
|
|
681
688
|
}
|
|
682
689
|
|
|
683
|
-
const
|
|
690
|
+
const device = devicesCache.find((d) => d.deviceId === publishModalDeviceId);
|
|
691
|
+
const alreadyOnDevice = (device?.publishedPlaylists || []).map((p) => p.playlistId);
|
|
692
|
+
const playlistIds = [...new Set([...alreadyOnDevice, ...ids])];
|
|
693
|
+
|
|
694
|
+
const publishBody = { playlistIds };
|
|
684
695
|
if (mediaBaseUrl) publishBody.mediaBaseUrl = mediaBaseUrl;
|
|
685
696
|
|
|
686
697
|
const res = await fetch(
|