yoto-nodejs-client 0.0.9 → 0.0.10
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/bin/device-model.js +10 -0
- package/lib/test-helpers/device-model-test-helpers.d.ts.map +1 -1
- package/lib/test-helpers/device-model-test-helpers.js +6 -0
- package/lib/yoto-device.d.ts +42 -2
- package/lib/yoto-device.d.ts.map +1 -1
- package/lib/yoto-device.js +67 -2
- package/lib/yoto-device.test.js +27 -2
- package/package.json +1 -1
package/bin/device-model.js
CHANGED
|
@@ -230,6 +230,7 @@ async function main () {
|
|
|
230
230
|
}
|
|
231
231
|
|
|
232
232
|
if (showFullState) {
|
|
233
|
+
const cardDuration = playback.cardDurationSeconds === null ? null : `${playback.cardDurationSeconds}s`
|
|
233
234
|
// Show full playback state
|
|
234
235
|
console.log(`\n${playbackIcon} PLAYBACK UPDATE [${timestamp}]: (FULL STATE)`)
|
|
235
236
|
console.log(` Status: ${playback.playbackStatus}`)
|
|
@@ -239,6 +240,12 @@ async function main () {
|
|
|
239
240
|
console.log(` Chapter Key: ${playback.chapterKey}`)
|
|
240
241
|
console.log(` Position: ${playback.position}/${playback.trackLength}s`)
|
|
241
242
|
console.log(` Card ID: ${playback.cardId}`)
|
|
243
|
+
console.log(` Card Title: ${playback.cardTitle}`)
|
|
244
|
+
console.log(` Card Slug: ${playback.cardSlug}`)
|
|
245
|
+
console.log(` Card Cover Image: ${playback.cardCoverImageUrl}`)
|
|
246
|
+
console.log(` Card Author: ${playback.cardAuthor}`)
|
|
247
|
+
console.log(` Card Read By: ${playback.cardReadBy}`)
|
|
248
|
+
console.log(` Card Duration: ${cardDuration}`)
|
|
242
249
|
console.log(` Source: ${playback.source}`)
|
|
243
250
|
console.log(` Streaming: ${playback.streaming}`)
|
|
244
251
|
console.log(` Sleep Timer Active: ${playback.sleepTimerActive}`)
|
|
@@ -257,6 +264,9 @@ async function main () {
|
|
|
257
264
|
// Skip if we already printed this combo
|
|
258
265
|
if (field === 'trackLength') continue
|
|
259
266
|
} else {
|
|
267
|
+
if (field === 'cardDurationSeconds' && typeof value === 'number') {
|
|
268
|
+
value = `${value}s`
|
|
269
|
+
}
|
|
260
270
|
console.log(` ${field}: ${value}`)
|
|
261
271
|
}
|
|
262
272
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"device-model-test-helpers.d.ts","sourceRoot":"","sources":["device-model-test-helpers.js"],"names":[],"mappings":"AAMA;;;;;GAKG;AACH,qCALW,OAAO,CAAC,OAAO,CAAC,aAChB,MAAM,SACN,MAAM,GACJ,OAAO,CAAC,OAAO,CAAC,CAS5B;AAED;;;GAGG;AACH,yCAHW,eAAe,GACb,OAAO,CAAC,IAAI,CAAC,CAUzB;AAED;;GAEG;AACH,0CAFW,qBAAqB,QAkD/B;AAED;;GAEG;AACH,8CAFW,iBAAiB,
|
|
1
|
+
{"version":3,"file":"device-model-test-helpers.d.ts","sourceRoot":"","sources":["device-model-test-helpers.js"],"names":[],"mappings":"AAMA;;;;;GAKG;AACH,qCALW,OAAO,CAAC,OAAO,CAAC,aAChB,MAAM,SACN,MAAM,GACJ,OAAO,CAAC,OAAO,CAAC,CAS5B;AAED;;;GAGG;AACH,yCAHW,eAAe,GACb,OAAO,CAAC,IAAI,CAAC,CAUzB;AAED;;GAEG;AACH,0CAFW,qBAAqB,QAkD/B;AAED;;GAEG;AACH,8CAFW,iBAAiB,QAwB3B;AAED;;;GAGG;AACH,+BAHW,MAAM,GAAG,SAAS,GAChB,MAAM,CAIlB;qCAzH8E,mBAAmB;2CAAnB,mBAAmB;uCAAnB,mBAAmB"}
|
|
@@ -94,6 +94,12 @@ export function assertPlaybackShape (playback) {
|
|
|
94
94
|
assert.equal(typeof playback.updatedAt, 'string', 'playback.updatedAt should be string')
|
|
95
95
|
|
|
96
96
|
assert.ok(playback.cardId === null || typeof playback.cardId === 'string', 'playback.cardId should be string or null')
|
|
97
|
+
assert.ok(playback.cardTitle === null || typeof playback.cardTitle === 'string', 'playback.cardTitle should be string or null')
|
|
98
|
+
assert.ok(playback.cardSlug === null || typeof playback.cardSlug === 'string', 'playback.cardSlug should be string or null')
|
|
99
|
+
assert.ok(playback.cardCoverImageUrl === null || typeof playback.cardCoverImageUrl === 'string', 'playback.cardCoverImageUrl should be string or null')
|
|
100
|
+
assert.ok(playback.cardAuthor === null || typeof playback.cardAuthor === 'string', 'playback.cardAuthor should be string or null')
|
|
101
|
+
assert.ok(playback.cardReadBy === null || typeof playback.cardReadBy === 'string', 'playback.cardReadBy should be string or null')
|
|
102
|
+
assert.ok(playback.cardDurationSeconds === null || typeof playback.cardDurationSeconds === 'number', 'playback.cardDurationSeconds should be number or null')
|
|
97
103
|
assert.ok(playback.source === null || typeof playback.source === 'string', 'playback.source should be string or null')
|
|
98
104
|
assert.ok(playback.playbackStatus === null || typeof playback.playbackStatus === 'string', 'playback.playbackStatus should be string or null')
|
|
99
105
|
assert.ok(playback.trackTitle === null || typeof playback.trackTitle === 'string', 'playback.trackTitle should be string or null')
|
package/lib/yoto-device.d.ts
CHANGED
|
@@ -102,6 +102,12 @@ export const YotoDeviceModelConfigType: {};
|
|
|
102
102
|
* Playback state from MQTT events
|
|
103
103
|
* @typedef {Object} YotoPlaybackState
|
|
104
104
|
* @property {string | null} cardId - Currently playing card ID TODO: Figure out name of card
|
|
105
|
+
* @property {string | null} cardTitle - Card title (from cached content)
|
|
106
|
+
* @property {string | null} cardSlug - Card slug (from cached content)
|
|
107
|
+
* @property {string | null} cardCoverImageUrl - Card cover image URL (from cached content)
|
|
108
|
+
* @property {string | null} cardAuthor - Card author (from cached content)
|
|
109
|
+
* @property {string | null} cardReadBy - Card narrator/reader (from cached content)
|
|
110
|
+
* @property {number | null} cardDurationSeconds - Total card duration in seconds (from cached content)
|
|
105
111
|
* @property {string | null} source - Playback source (e.g., 'card', 'remote', 'MQTT') TODO: Figure out what 'mqtt' source means. Card means card, remote means remotly played card.
|
|
106
112
|
* @property {PlaybackStatus | null} playbackStatus - Playback status
|
|
107
113
|
* @property {string | null} trackTitle - Current track title
|
|
@@ -135,7 +141,12 @@ export const YotoPlaybackStateType: {};
|
|
|
135
141
|
* Cached card metadata for playback enrichment.
|
|
136
142
|
* @typedef {Object} YotoCardCacheEntry
|
|
137
143
|
* @property {string} cardId
|
|
138
|
-
* @property {string}
|
|
144
|
+
* @property {string} cardTitle
|
|
145
|
+
* @property {string | null} cardSlug
|
|
146
|
+
* @property {string | null} cardCoverImageUrl
|
|
147
|
+
* @property {string | null} cardAuthor
|
|
148
|
+
* @property {string | null} cardReadBy
|
|
149
|
+
* @property {number | null} cardDurationSeconds
|
|
139
150
|
* @property {Map<string, YotoCardCacheChapterInfo>} chaptersByKey
|
|
140
151
|
* @property {Map<string, YotoCardCacheTrackInfo>} tracksByKey
|
|
141
152
|
*/
|
|
@@ -824,6 +835,30 @@ export type YotoPlaybackState = {
|
|
|
824
835
|
* - Currently playing card ID TODO: Figure out name of card
|
|
825
836
|
*/
|
|
826
837
|
cardId: string | null;
|
|
838
|
+
/**
|
|
839
|
+
* - Card title (from cached content)
|
|
840
|
+
*/
|
|
841
|
+
cardTitle: string | null;
|
|
842
|
+
/**
|
|
843
|
+
* - Card slug (from cached content)
|
|
844
|
+
*/
|
|
845
|
+
cardSlug: string | null;
|
|
846
|
+
/**
|
|
847
|
+
* - Card cover image URL (from cached content)
|
|
848
|
+
*/
|
|
849
|
+
cardCoverImageUrl: string | null;
|
|
850
|
+
/**
|
|
851
|
+
* - Card author (from cached content)
|
|
852
|
+
*/
|
|
853
|
+
cardAuthor: string | null;
|
|
854
|
+
/**
|
|
855
|
+
* - Card narrator/reader (from cached content)
|
|
856
|
+
*/
|
|
857
|
+
cardReadBy: string | null;
|
|
858
|
+
/**
|
|
859
|
+
* - Total card duration in seconds (from cached content)
|
|
860
|
+
*/
|
|
861
|
+
cardDurationSeconds: number | null;
|
|
827
862
|
/**
|
|
828
863
|
* - Playback source (e.g., 'card', 'remote', 'MQTT') TODO: Figure out what 'mqtt' source means. Card means card, remote means remotly played card.
|
|
829
864
|
*/
|
|
@@ -895,7 +930,12 @@ export type YotoCardCacheTrackInfo = {
|
|
|
895
930
|
*/
|
|
896
931
|
export type YotoCardCacheEntry = {
|
|
897
932
|
cardId: string;
|
|
898
|
-
|
|
933
|
+
cardTitle: string;
|
|
934
|
+
cardSlug: string | null;
|
|
935
|
+
cardCoverImageUrl: string | null;
|
|
936
|
+
cardAuthor: string | null;
|
|
937
|
+
cardReadBy: string | null;
|
|
938
|
+
cardDurationSeconds: number | null;
|
|
899
939
|
chaptersByKey: Map<string, YotoCardCacheChapterInfo>;
|
|
900
940
|
tracksByKey: Map<string, YotoCardCacheTrackInfo>;
|
|
901
941
|
};
|
package/lib/yoto-device.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"yoto-device.d.ts","sourceRoot":"","sources":["yoto-device.js"],"names":[],"mappings":"AAoTA;;;;GAIG;AACH,mDAHW,MAAM,GACJ,MAAM,CAIlB;AAxBD;;;;GAIG;AACH;;;;;;;;;;EAUC;AAWD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,sCAAsC;AAEtC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AACH,2CAA2C;AAE3C
|
|
1
|
+
{"version":3,"file":"yoto-device.d.ts","sourceRoot":"","sources":["yoto-device.js"],"names":[],"mappings":"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"}
|
package/lib/yoto-device.js
CHANGED
|
@@ -399,6 +399,12 @@ export const YotoDeviceModelConfigType = {}
|
|
|
399
399
|
* Playback state from MQTT events
|
|
400
400
|
* @typedef {Object} YotoPlaybackState
|
|
401
401
|
* @property {string | null} cardId - Currently playing card ID TODO: Figure out name of card
|
|
402
|
+
* @property {string | null} cardTitle - Card title (from cached content)
|
|
403
|
+
* @property {string | null} cardSlug - Card slug (from cached content)
|
|
404
|
+
* @property {string | null} cardCoverImageUrl - Card cover image URL (from cached content)
|
|
405
|
+
* @property {string | null} cardAuthor - Card author (from cached content)
|
|
406
|
+
* @property {string | null} cardReadBy - Card narrator/reader (from cached content)
|
|
407
|
+
* @property {number | null} cardDurationSeconds - Total card duration in seconds (from cached content)
|
|
402
408
|
* @property {string | null} source - Playback source (e.g., 'card', 'remote', 'MQTT') TODO: Figure out what 'mqtt' source means. Card means card, remote means remotly played card.
|
|
403
409
|
* @property {PlaybackStatus | null} playbackStatus - Playback status
|
|
404
410
|
* @property {string | null} trackTitle - Current track title
|
|
@@ -439,7 +445,12 @@ export const YotoPlaybackStateType = {}
|
|
|
439
445
|
* Cached card metadata for playback enrichment.
|
|
440
446
|
* @typedef {Object} YotoCardCacheEntry
|
|
441
447
|
* @property {string} cardId
|
|
442
|
-
* @property {string}
|
|
448
|
+
* @property {string} cardTitle
|
|
449
|
+
* @property {string | null} cardSlug
|
|
450
|
+
* @property {string | null} cardCoverImageUrl
|
|
451
|
+
* @property {string | null} cardAuthor
|
|
452
|
+
* @property {string | null} cardReadBy
|
|
453
|
+
* @property {number | null} cardDurationSeconds
|
|
443
454
|
* @property {Map<string, YotoCardCacheChapterInfo>} chaptersByKey
|
|
444
455
|
* @property {Map<string, YotoCardCacheTrackInfo>} tracksByKey
|
|
445
456
|
*/
|
|
@@ -3433,6 +3444,12 @@ export class YotoDeviceModel extends EventEmitter {
|
|
|
3433
3444
|
function createEmptyPlaybackState () {
|
|
3434
3445
|
return {
|
|
3435
3446
|
cardId: null,
|
|
3447
|
+
cardTitle: null,
|
|
3448
|
+
cardSlug: null,
|
|
3449
|
+
cardCoverImageUrl: null,
|
|
3450
|
+
cardAuthor: null,
|
|
3451
|
+
cardReadBy: null,
|
|
3452
|
+
cardDurationSeconds: null,
|
|
3436
3453
|
source: null,
|
|
3437
3454
|
playbackStatus: null,
|
|
3438
3455
|
trackTitle: null,
|
|
@@ -3481,9 +3498,20 @@ function buildCardCacheEntry (card) {
|
|
|
3481
3498
|
}
|
|
3482
3499
|
}
|
|
3483
3500
|
|
|
3501
|
+
const cardCoverImageUrl = card.metadata?.cover?.imageL ?? null
|
|
3502
|
+
const cardAuthor = card.metadata?.author ?? null
|
|
3503
|
+
const cardReadBy = card.metadata?.readBy ?? null
|
|
3504
|
+
const cardDurationSeconds = Number.isFinite(card.metadata?.media?.duration) ? card.metadata.media.duration : null
|
|
3505
|
+
const cardSlug = card.slug || null
|
|
3506
|
+
|
|
3484
3507
|
return {
|
|
3485
3508
|
cardId: card.cardId,
|
|
3486
|
-
|
|
3509
|
+
cardTitle: card.title,
|
|
3510
|
+
cardSlug,
|
|
3511
|
+
cardCoverImageUrl,
|
|
3512
|
+
cardAuthor,
|
|
3513
|
+
cardReadBy,
|
|
3514
|
+
cardDurationSeconds,
|
|
3487
3515
|
chaptersByKey,
|
|
3488
3516
|
tracksByKey
|
|
3489
3517
|
}
|
|
@@ -3497,6 +3525,43 @@ function buildCardCacheEntry (card) {
|
|
|
3497
3525
|
*/
|
|
3498
3526
|
function applyCardCacheToPlayback (entry, playback, changedFields) {
|
|
3499
3527
|
let changed = false
|
|
3528
|
+
|
|
3529
|
+
if (playback.cardTitle !== entry.cardTitle) {
|
|
3530
|
+
playback.cardTitle = entry.cardTitle
|
|
3531
|
+
changedFields.add('cardTitle')
|
|
3532
|
+
changed = true
|
|
3533
|
+
}
|
|
3534
|
+
|
|
3535
|
+
if (playback.cardSlug !== entry.cardSlug) {
|
|
3536
|
+
playback.cardSlug = entry.cardSlug
|
|
3537
|
+
changedFields.add('cardSlug')
|
|
3538
|
+
changed = true
|
|
3539
|
+
}
|
|
3540
|
+
|
|
3541
|
+
if (playback.cardCoverImageUrl !== entry.cardCoverImageUrl) {
|
|
3542
|
+
playback.cardCoverImageUrl = entry.cardCoverImageUrl
|
|
3543
|
+
changedFields.add('cardCoverImageUrl')
|
|
3544
|
+
changed = true
|
|
3545
|
+
}
|
|
3546
|
+
|
|
3547
|
+
if (playback.cardAuthor !== entry.cardAuthor) {
|
|
3548
|
+
playback.cardAuthor = entry.cardAuthor
|
|
3549
|
+
changedFields.add('cardAuthor')
|
|
3550
|
+
changed = true
|
|
3551
|
+
}
|
|
3552
|
+
|
|
3553
|
+
if (playback.cardReadBy !== entry.cardReadBy) {
|
|
3554
|
+
playback.cardReadBy = entry.cardReadBy
|
|
3555
|
+
changedFields.add('cardReadBy')
|
|
3556
|
+
changed = true
|
|
3557
|
+
}
|
|
3558
|
+
|
|
3559
|
+
if (playback.cardDurationSeconds !== entry.cardDurationSeconds) {
|
|
3560
|
+
playback.cardDurationSeconds = entry.cardDurationSeconds
|
|
3561
|
+
changedFields.add('cardDurationSeconds')
|
|
3562
|
+
changed = true
|
|
3563
|
+
}
|
|
3564
|
+
|
|
3500
3565
|
const { trackKey } = playback
|
|
3501
3566
|
|
|
3502
3567
|
if (trackKey) {
|
package/lib/yoto-device.test.js
CHANGED
|
@@ -21,6 +21,12 @@ const PLAYBACK_SAMPLE_SCAN_LIMIT = 5
|
|
|
21
21
|
/**
|
|
22
22
|
* @typedef {Object} PlaybackSample
|
|
23
23
|
* @property {string} cardId
|
|
24
|
+
* @property {string} cardTitle
|
|
25
|
+
* @property {string | null} cardSlug
|
|
26
|
+
* @property {string | null} cardCoverImageUrl
|
|
27
|
+
* @property {string | null} cardAuthor
|
|
28
|
+
* @property {string | null} cardReadBy
|
|
29
|
+
* @property {number | null} cardDurationSeconds
|
|
24
30
|
* @property {Map<string, { title: string, duration: number, chapterKey: string, chapterTitle: string }>} tracksByKey
|
|
25
31
|
* @property {string} chapterKey
|
|
26
32
|
* @property {string} chapterTitle
|
|
@@ -86,7 +92,14 @@ async function findPlaybackSample (client) {
|
|
|
86
92
|
|
|
87
93
|
try {
|
|
88
94
|
const contentResponse = await client.getContent({ cardId: card.cardId })
|
|
89
|
-
const
|
|
95
|
+
const contentCard = contentResponse.card
|
|
96
|
+
const metadata = contentCard.metadata
|
|
97
|
+
const cardCoverImageUrl = metadata?.cover?.imageL ?? null
|
|
98
|
+
const cardAuthor = metadata?.author ?? null
|
|
99
|
+
const cardReadBy = metadata?.readBy ?? null
|
|
100
|
+
const cardDurationSeconds = Number.isFinite(metadata?.media?.duration) ? metadata.media.duration : null
|
|
101
|
+
const cardSlug = contentCard.slug || null
|
|
102
|
+
const chapters = contentCard.content.chapters
|
|
90
103
|
const firstChapter = chapters.find(candidate => candidate.tracks.length > 0)
|
|
91
104
|
|
|
92
105
|
if (!firstChapter) {
|
|
@@ -117,7 +130,13 @@ async function findPlaybackSample (client) {
|
|
|
117
130
|
}
|
|
118
131
|
|
|
119
132
|
return {
|
|
120
|
-
cardId:
|
|
133
|
+
cardId: contentCard.cardId,
|
|
134
|
+
cardTitle: contentCard.title,
|
|
135
|
+
cardSlug,
|
|
136
|
+
cardCoverImageUrl,
|
|
137
|
+
cardAuthor,
|
|
138
|
+
cardReadBy,
|
|
139
|
+
cardDurationSeconds,
|
|
121
140
|
tracksByKey,
|
|
122
141
|
chapterKey: firstChapter.key,
|
|
123
142
|
chapterTitle: firstChapter.title,
|
|
@@ -284,6 +303,12 @@ test('YotoDeviceModel - playback normalization', async (t) => {
|
|
|
284
303
|
assert.equal(cachePlayback.trackLength, trackInfo.duration)
|
|
285
304
|
assert.equal(cachePlayback.chapterKey, trackInfo.chapterKey)
|
|
286
305
|
assert.equal(cachePlayback.chapterTitle, trackInfo.chapterTitle)
|
|
306
|
+
assert.equal(cachePlayback.cardTitle, sample.cardTitle)
|
|
307
|
+
assert.equal(cachePlayback.cardSlug, sample.cardSlug)
|
|
308
|
+
assert.equal(cachePlayback.cardCoverImageUrl, sample.cardCoverImageUrl)
|
|
309
|
+
assert.equal(cachePlayback.cardAuthor, sample.cardAuthor)
|
|
310
|
+
assert.equal(cachePlayback.cardReadBy, sample.cardReadBy)
|
|
311
|
+
assert.equal(cachePlayback.cardDurationSeconds, sample.cardDurationSeconds)
|
|
287
312
|
})
|
|
288
313
|
|
|
289
314
|
await t.test('cardId none normalization', async () => {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "yoto-nodejs-client",
|
|
3
3
|
"description": "(Unofficial) Node.js client for the Yoto API with automatic token refresh, MQTT device communication, and TypeScript support",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.10",
|
|
5
5
|
"author": "Bret Comnes <bcomnes@gmail.com> (https://bret.io)",
|
|
6
6
|
"bugs": {
|
|
7
7
|
"url": "https://github.com/bcomnes/yoto-nodejs-client/issues"
|