homebridge-yoto 0.0.13 → 0.0.14
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/lib/platform.js +41 -0
- package/lib/playerAccessory.js +9 -1
- package/lib/yotoApi.js +11 -2
- package/package.json +1 -1
package/lib/platform.js
CHANGED
|
@@ -56,6 +56,10 @@ export class YotoPlatform {
|
|
|
56
56
|
// Status polling interval
|
|
57
57
|
this.statusPollInterval = null
|
|
58
58
|
|
|
59
|
+
// Cache of user's owned MYO card IDs
|
|
60
|
+
/** @type {Set<string>} */
|
|
61
|
+
this.ownedCardIds = new Set()
|
|
62
|
+
|
|
59
63
|
// Initialize API clients
|
|
60
64
|
this.auth = new YotoAuth(log, this.config.clientId)
|
|
61
65
|
this.yotoApi = new YotoApi(log, this.auth)
|
|
@@ -108,6 +112,9 @@ export class YotoPlatform {
|
|
|
108
112
|
throw error
|
|
109
113
|
}
|
|
110
114
|
|
|
115
|
+
// Fetch user's owned cards for lookup optimization
|
|
116
|
+
await this.fetchOwnedCards()
|
|
117
|
+
|
|
111
118
|
// Start platform-level status polling (every 60 seconds)
|
|
112
119
|
this.startStatusPolling()
|
|
113
120
|
} catch (error) {
|
|
@@ -173,6 +180,40 @@ export class YotoPlatform {
|
|
|
173
180
|
}
|
|
174
181
|
|
|
175
182
|
/**
|
|
183
|
+
* Fetch user's owned MYO cards and cache their IDs
|
|
184
|
+
* @returns {Promise<void>}
|
|
185
|
+
*/
|
|
186
|
+
async fetchOwnedCards () {
|
|
187
|
+
try {
|
|
188
|
+
this.log.debug(LOG_PREFIX.PLATFORM, 'Fetching user\'s owned cards...')
|
|
189
|
+
const myContent = await this.yotoApi.getMyContent()
|
|
190
|
+
|
|
191
|
+
// Cache card IDs
|
|
192
|
+
if (myContent.cards && Array.isArray(myContent.cards)) {
|
|
193
|
+
this.ownedCardIds.clear()
|
|
194
|
+
for (const card of myContent.cards) {
|
|
195
|
+
if (card.cardId) {
|
|
196
|
+
this.ownedCardIds.add(card.cardId)
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
this.log.info(LOG_PREFIX.PLATFORM, `✓ Cached ${this.ownedCardIds.size} owned card(s)`)
|
|
200
|
+
}
|
|
201
|
+
} catch (error) {
|
|
202
|
+
this.log.warn(LOG_PREFIX.PLATFORM, 'Failed to fetch owned cards, card details may be limited:', error)
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Check if a card is owned by the user
|
|
208
|
+
* @param {string} cardId - Card ID to check
|
|
209
|
+
* @returns {boolean}
|
|
210
|
+
*/
|
|
211
|
+
isCardOwned (cardId) {
|
|
212
|
+
return this.ownedCardIds.has(cardId)
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Handle token refresh - update config
|
|
176
217
|
* Perform device authorization flow
|
|
177
218
|
* @returns {Promise<void>}
|
|
178
219
|
*/
|
package/lib/playerAccessory.js
CHANGED
|
@@ -1536,10 +1536,18 @@ export class YotoPlayerAccessory {
|
|
|
1536
1536
|
return
|
|
1537
1537
|
}
|
|
1538
1538
|
|
|
1539
|
+
// Check if we own this card before attempting to fetch details
|
|
1540
|
+
if (!this.platform.isCardOwned(cardId)) {
|
|
1541
|
+
this.log.info(LOG_PREFIX.ACCESSORY, `[${this.device.name}] Playing card ${cardId} (store content - details not available)`)
|
|
1542
|
+
this.activeContentInfo = null
|
|
1543
|
+
this.accessory.context.activeContentInfo = null
|
|
1544
|
+
return
|
|
1545
|
+
}
|
|
1546
|
+
|
|
1539
1547
|
this.log.info(LOG_PREFIX.ACCESSORY, `[${this.device.name}] Active card changed: ${cardId}`)
|
|
1540
1548
|
|
|
1541
1549
|
try {
|
|
1542
|
-
// Fetch card details
|
|
1550
|
+
// Fetch card details for owned cards
|
|
1543
1551
|
const content = await this.platform.yotoApi.getContent(cardId)
|
|
1544
1552
|
this.activeContentInfo = content
|
|
1545
1553
|
|
package/lib/yotoApi.js
CHANGED
|
@@ -114,7 +114,6 @@ export class YotoApi {
|
|
|
114
114
|
|
|
115
115
|
if (!response.ok) {
|
|
116
116
|
const errorText = await response.text()
|
|
117
|
-
this.log.error(LOG_PREFIX.API, `Request failed: ${response.status} ${errorText}`)
|
|
118
117
|
|
|
119
118
|
// Handle 401 by attempting token refresh once
|
|
120
119
|
if (response.status === 401 && !options._retried) {
|
|
@@ -124,6 +123,13 @@ export class YotoApi {
|
|
|
124
123
|
return this.request(endpoint, { ...options, _retried: true })
|
|
125
124
|
}
|
|
126
125
|
|
|
126
|
+
// Reduce noise for expected errors (403/404 on content endpoints)
|
|
127
|
+
if ((response.status === 403 || response.status === 404) && endpoint.startsWith('/content/')) {
|
|
128
|
+
this.log.debug(LOG_PREFIX.API, `Request failed: ${response.status} ${errorText}`)
|
|
129
|
+
} else {
|
|
130
|
+
this.log.error(LOG_PREFIX.API, `Request failed: ${response.status} ${errorText}`)
|
|
131
|
+
}
|
|
132
|
+
|
|
127
133
|
throw new Error(`API request failed: ${response.status} ${errorText}`)
|
|
128
134
|
}
|
|
129
135
|
|
|
@@ -134,7 +140,10 @@ export class YotoApi {
|
|
|
134
140
|
|
|
135
141
|
return await response.json()
|
|
136
142
|
} catch (error) {
|
|
137
|
-
|
|
143
|
+
// Only log non-API errors (network issues, etc.)
|
|
144
|
+
if (!(error instanceof Error && error.message.startsWith('API request failed'))) {
|
|
145
|
+
this.log.error(LOG_PREFIX.API, `${ERROR_MESSAGES.API_ERROR}:`, error)
|
|
146
|
+
}
|
|
138
147
|
throw error
|
|
139
148
|
}
|
|
140
149
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "homebridge-yoto",
|
|
3
3
|
"description": "Control your Yoto players through Apple HomeKit with real-time MQTT updates",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.14",
|
|
5
5
|
"author": "Bret Comnes <bcomnes@gmail.com> (https://bret.io)",
|
|
6
6
|
"bugs": {
|
|
7
7
|
"url": "https://github.com/bcomnes/homebridge-yoto/issues"
|