const axios = require("axios"); const logger = require("./logging"); const fs = require("fs/promises"); const Song = require("../../models/song"); class SpotifyTracker { constructor(config, token) { this._token = token; this._cache = null; this._config = config; this._auth = new Buffer.from(config.client_id + ':' + config.client_secret).toString('base64'); } async poll(useCache = false) { if (token == null) return null; if (useCache) return cache; if (token.expires_at < Date.now() + 300) await this.#refreshTokenIfNeeded(); try { const response = await axios.get("https://api.spotify.com/v1/me/player/currently-playing", { headers: { "Authorization": "Bearer " + token["access_token"] } } ); if (!response.data) { cache = null; return null; } cache = [this.#transform(response.data)]; return cache; } catch (ex) { logger.error(ex, "Failed to get currently playing data from Spotify."); return []; } } #transform(data) { const item = data.item; const artists = item.artists.map(a => a.name); const year = null; const state = data.is_playing ? "playing" : "paused"; return new Song(item.id, item.name, item.album.name, artists, year, item.duration_ms, data.progress_ms, "spotify", state, "spotify"); } async #refreshTokenIfNeeded() { if (!this._token || this._token.expires_at && this._token.expires_at - Date.now() > 900) return false; const response = await axios.post("https://accounts.spotify.com/api/token", { client_id: this._config.client_id, refresh_token: this._token.refresh_token, grant_type: "refresh_token" }, { headers: { "Authorization": "Basic " + this._auth, "Content-Type": "application/x-www-form-urlencoded" } } ); const data = response.data; data["expires_at"] = Date.now() + data["expires_in"] * 1000; if (!data["refresh_token"]) data["refresh_token"] = this._token.refresh_token; this._token = data; await fs.writeFile("credentials.spotify.json", JSON.stringify(data)); logger.debug("Updated access token for Spotify."); return true; } } module.exports = SpotifyTracker;