apollo/services/trackers/spotify-tracker.js

107 lines
2.9 KiB
JavaScript
Raw Permalink Normal View History

2024-12-04 23:18:35 -05:00
const axios = require("axios");
2024-12-05 03:26:31 -05:00
const logger = require("../logging");
2024-12-04 23:18:35 -05:00
const fs = require("fs/promises");
2024-12-05 03:26:31 -05:00
const fss = require("fs");
2024-12-04 23:18:35 -05:00
const Song = require("../../models/song");
class SpotifyTracker {
2024-12-05 03:26:31 -05:00
#config = null;
#token = null;
#cache = [];
2024-12-05 03:26:31 -05:00
#auth = null;
provider = "spotify";
2024-12-05 03:26:31 -05:00
constructor(config, token = null) {
this.#config = config;
this.#token = token;
this.#auth = new Buffer.from(config.client_id + ':' + config.client_secret).toString('base64');
2024-12-04 23:18:35 -05:00
}
get name() {
return this.#config.name;
}
get scrobblerNames() {
return this.#config.scrobblers;
}
2024-12-04 23:18:35 -05:00
async poll(useCache = false) {
2024-12-05 03:26:31 -05:00
if (this.#token == null)
return [];
2024-12-04 23:18:35 -05:00
if (useCache)
2024-12-05 03:26:31 -05:00
return this.#cache;
2024-12-04 23:18:35 -05:00
2024-12-05 03:26:31 -05:00
if (this.#token.expires_at < Date.now() + 300)
2024-12-04 23:18:35 -05:00
await this.#refreshTokenIfNeeded();
try {
const response = await axios.get("https://api.spotify.com/v1/me/player/currently-playing",
{
headers: {
2024-12-05 03:26:31 -05:00
"Authorization": "Bearer " + this.#token.access_token
2024-12-04 23:18:35 -05:00
}
}
);
if (!response.data) {
2024-12-05 03:26:31 -05:00
this.#cache = [];
return this.#cache;
2024-12-04 23:18:35 -05:00
}
this.#cache = [this.#transform(response.data, this.#config.name)];
2024-12-05 03:26:31 -05:00
return this.#cache;
2024-12-04 23:18:35 -05:00
} catch (ex) {
logger.error(ex, "Failed to get currently playing data from Spotify.");
return [];
}
}
2024-12-05 03:26:31 -05:00
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) {
2024-12-04 23:18:35 -05:00
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");
2024-12-04 23:18:35 -05:00
}
async #refreshTokenIfNeeded() {
2024-12-05 03:26:31 -05:00
if (!this.#token || this.#token.expires_at && this.#token.expires_at - Date.now() > 900)
2024-12-04 23:18:35 -05:00
return false;
const response = await axios.post("https://accounts.spotify.com/api/token",
{
2024-12-05 03:26:31 -05:00
client_id: this.#config.client_id,
refresh_token: this.#token.refresh_token,
2024-12-04 23:18:35 -05:00
grant_type: "refresh_token"
},
{
headers: {
2024-12-05 03:26:31 -05:00
"Authorization": "Basic " + this.#auth,
2024-12-04 23:18:35 -05:00
"Content-Type": "application/x-www-form-urlencoded"
}
}
);
const data = response.data;
data["expires_at"] = Date.now() + data["expires_in"] * 1000;
if (!data["refresh_token"])
2024-12-05 03:26:31 -05:00
data["refresh_token"] = this.#token.refresh_token;
2024-12-04 23:18:35 -05:00
2024-12-05 03:26:31 -05:00
this.#token = data;
2024-12-04 23:18:35 -05:00
await fs.writeFile("credentials.spotify.json", JSON.stringify(data));
logger.debug("Updated access token for Spotify.");
return true;
}
}
module.exports = SpotifyTracker;