apollo/services/trackers/spotify-tracker.js

107 lines
2.9 KiB
JavaScript

const axios = require("axios");
const logger = require("../logging");
const fs = require("fs/promises");
const fss = require("fs");
const Song = require("../../models/song");
class SpotifyTracker {
#config = null;
#token = null;
#cache = [];
#auth = null;
provider = "spotify";
constructor(config, token = null) {
this.#config = config;
this.#token = token;
this.#auth = new Buffer.from(config.client_id + ':' + config.client_secret).toString('base64');
}
get name() {
return this.#config.name;
}
get scrobblerNames() {
return this.#config.scrobblers;
}
async poll(useCache = false) {
if (this.#token == null)
return [];
if (useCache)
return this.#cache;
if (this.#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 " + this.#token.access_token
}
}
);
if (!response.data) {
this.#cache = [];
return this.#cache;
}
this.#cache = [this.#transform(response.data, this.#config.name)];
return this.#cache;
} catch (ex) {
logger.error(ex, "Failed to get currently playing data from Spotify.");
return [];
}
}
async loadCredentials() {
if (!fss.existsSync("credentials.spotify.json")) {
logger.info("No Spotify credentials found.");
return;
}
const content = await fs.readFile("credentials.spotify.json", "utf-8");
this.#token = JSON.parse(content);
}
#transform(data, source) {
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, source, "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;