@@ -4,7 +4,7 @@ import { SpotifyDeviceNotFoundError } from './errors';
4
4
5
5
import type { API , Logger , PlatformConfig } from 'homebridge' ;
6
6
import type { HomebridgeSpotifySpeakerDevice } from './spotify-speaker-accessory' ;
7
- import type { SpotifyPlaybackState , WebapiError } from './types' ;
7
+ import { SpotifyPlaybackState , WebapiError } from './types' ;
8
8
9
9
const DEFAULT_SPOTIFY_CALLBACK = 'https://example.com/callback' ;
10
10
@@ -95,13 +95,21 @@ export class SpotifyApiWrapper {
95
95
await this . wrappedRequest ( ( ) => this . spotifyApi . setVolume ( volume , { device_id : deviceId } ) ) ;
96
96
}
97
97
98
- async getMyDevices ( ) {
98
+ async getMyDevices ( isFirstAttempt = true ) : Promise < SpotifyApi . UserDevice [ ] > {
99
99
try {
100
100
const res = await this . spotifyApi . getMyDevices ( ) ;
101
101
return res . body . devices ;
102
102
} catch ( error ) {
103
- this . log . error ( 'Failed to fetch available Spotify devices.' ) ;
104
- return null ;
103
+ if ( isFirstAttempt ) {
104
+ return new Promise ( ( resolve ) => {
105
+ setTimeout ( ( ) => {
106
+ this . getMyDevices ( false ) . then ( resolve ) ;
107
+ } , 500 ) ;
108
+ } ) ;
109
+ } else {
110
+ this . log . error ( 'Failed to fetch available Spotify devices.' , error ) ;
111
+ return [ ] ;
112
+ }
105
113
}
106
114
}
107
115
@@ -158,29 +166,33 @@ export class SpotifyApiWrapper {
158
166
return true ;
159
167
}
160
168
161
- private async wrappedRequest < T > ( cb : ( ) => Promise < T > ) : Promise < T | undefined > {
169
+ private async wrappedRequest < T > ( cb : ( ) => Promise < T > , isFirstAttempt = true ) : Promise < T | undefined > {
162
170
try {
163
171
const response = await cb ( ) ;
164
172
return response ;
165
173
} catch ( error : unknown ) {
166
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
167
- const isWebApiError = Object . getPrototypeOf ( ( error as any ) . constructor ) . name === 'WebapiError' ;
168
-
169
- if ( isWebApiError ) {
170
- if ( ( error as WebapiError ) . statusCode === 401 ) {
174
+ let errorMessage = error ;
175
+ if ( isWebApiError ( error ) && isFirstAttempt ) {
176
+ const webApiError = error as WebapiError ;
177
+ if ( webApiError . statusCode === 401 ) {
171
178
this . log . debug ( 'Access token has expired, attempting token refresh' ) ;
172
179
173
180
const areTokensRefreshed = await this . refreshTokens ( ) ;
174
181
if ( areTokensRefreshed ) {
175
- return this . wrappedRequest ( cb ) ;
182
+ return this . wrappedRequest ( cb , false ) ;
176
183
}
177
- } else if ( ( error as WebapiError ) . statusCode === 404 ) {
178
- throw new SpotifyDeviceNotFoundError ( ) ;
184
+ } else if ( webApiError . statusCode === 404 ) {
185
+ return this . wrappedRequest ( cb , false ) ;
179
186
}
187
+ errorMessage = webApiError . body ;
180
188
}
181
189
182
- const errorMessage = isWebApiError ? ( error as WebapiError ) . body : error ;
183
190
this . log . error ( 'Unexpected error when making a request to Spotify:' , JSON . stringify ( errorMessage ) ) ;
184
191
}
185
192
}
186
193
}
194
+
195
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
196
+ function isWebApiError ( error : any ) : boolean {
197
+ return error . constructor . name === 'WebapiError' || Object . getPrototypeOf ( error . constructor ) . name === 'WebapiError' ;
198
+ }
0 commit comments