diff --git a/services/trackers/AggregateTracker.js b/services/trackers/AggregateTracker.js index 41afe97..ef479f1 100644 --- a/services/trackers/AggregateTracker.js +++ b/services/trackers/AggregateTracker.js @@ -1,13 +1,17 @@ class AggregateTracker { + #trackers = [] + constructor(trackers) { - this._trackers = trackers; + this.#trackers = trackers; } - poll() { - const media = [] - for (let tracker of this._trackers) - media.push.apply(tracker.poll()); + async poll() { + let media = [] + for (let tracker of this.#trackers) + media = media.concat(await tracker.poll()); return media; } -} \ No newline at end of file +} + +module.exports = AggregateTracker; \ No newline at end of file diff --git a/services/trackers/PlexTracker.js b/services/trackers/PlexTracker.js index 9a41155..2041acf 100644 --- a/services/trackers/PlexTracker.js +++ b/services/trackers/PlexTracker.js @@ -2,39 +2,41 @@ const axios = require("axios"); const Song = require("../../models/song"); class PlexTracker { + #config = null; + #cache = []; + constructor(config) { - this._config = config; - this._cache = [] + this.#config = config; } async poll(useCache = false) { - if (!this._config.token || !this._config.url) + if (!this.#config.token || !this.#config.url) return []; if (useCache) - return cache; + return this.#cache; - const response = await axios.get(this._config.url + "/status/sessions", { + const response = await axios.get(this.#config.url + "/status/sessions", { headers: { "Accept": "application/json", - "X-Plex-Token": this._config.token + "X-Plex-Token": this.#config.token } }); if (!response.data.MediaContainer?.Metadata) { - cache = []; - return cache; + this.#cache = []; + return this.#cache; } const filtered = response.data.MediaContainer?.Metadata.filter(m => this.#filter(m)); - cache = filtered.map(this.#transform); - return cache; + this.#cache = filtered.map(m => this.#transform(m)); + return this.#cache; } #filter(data) { - if (!this._config.filters || this._config.filters.length == 0) + if (!this.#config.filters || this.#config.filters.length == 0) return true; - for (let filter of this._config.filters) { + for (let filter of this.#config.filters) { if (filter.library && !filter.library.some(l => l == data.librarySectionTitle)) continue; if (filter.ip && !filter.ip.some(l => l == data.address)) diff --git a/services/trackers/SpotifyTracker.js b/services/trackers/SpotifyTracker.js index 5fc38aa..db52a6e 100644 --- a/services/trackers/SpotifyTracker.js +++ b/services/trackers/SpotifyTracker.js @@ -1,47 +1,63 @@ const axios = require("axios"); -const logger = require("./logging"); +const logger = require("../logging"); const fs = require("fs/promises"); +const fss = require("fs"); 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'); + #config = null; + #token = null; + #cache = null; + #auth = null; + + constructor(config, token = null) { + this.#config = config; + this.#token = token; + this.#cache = null; + this.#auth = new Buffer.from(config.client_id + ':' + config.client_secret).toString('base64'); } async poll(useCache = false) { - if (token == null) - return null; + if (this.#token == null) + return []; if (useCache) - return cache; + return this.#cache; - if (token.expires_at < Date.now() + 300) + 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 " + token["access_token"] + "Authorization": "Bearer " + this.#token.access_token } } ); if (!response.data) { - cache = null; - return null; + this.#cache = []; + return this.#cache; } - cache = [this.#transform(response.data)]; - return cache; + this.#cache = [this.#transform(response.data)]; + 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) { const item = data.item; const artists = item.artists.map(a => a.name); @@ -51,18 +67,18 @@ class SpotifyTracker { } async #refreshTokenIfNeeded() { - if (!this._token || this._token.expires_at && this._token.expires_at - Date.now() > 900) + 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, + client_id: this.#config.client_id, + refresh_token: this.#token.refresh_token, grant_type: "refresh_token" }, { headers: { - "Authorization": "Basic " + this._auth, + "Authorization": "Basic " + this.#auth, "Content-Type": "application/x-www-form-urlencoded" } } @@ -71,9 +87,9 @@ class SpotifyTracker { const data = response.data; data["expires_at"] = Date.now() + data["expires_in"] * 1000; if (!data["refresh_token"]) - data["refresh_token"] = this._token.refresh_token; + data["refresh_token"] = this.#token.refresh_token; - this._token = data; + this.#token = data; await fs.writeFile("credentials.spotify.json", JSON.stringify(data)); logger.debug("Updated access token for Spotify."); return true;