Added song data class. Added trackers.
This commit is contained in:
parent
539b9a5055
commit
6e43d681da
16
models/song.js
Normal file
16
models/song.js
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
class Song {
|
||||||
|
constructor(id, name, album, artists, year, duration, progress, session, state, source) {
|
||||||
|
this.id = id;
|
||||||
|
this.name = name;
|
||||||
|
this.album = album;
|
||||||
|
this.artists = artists;
|
||||||
|
this.year = year;
|
||||||
|
this.duration = duration;
|
||||||
|
this.progress = progress;
|
||||||
|
this.session = session;
|
||||||
|
this.state = state;
|
||||||
|
this.source = source;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Song;
|
13
services/trackers/AggregateTracker.js
Normal file
13
services/trackers/AggregateTracker.js
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
class AggregateTracker {
|
||||||
|
constructor(trackers) {
|
||||||
|
this._trackers = trackers;
|
||||||
|
}
|
||||||
|
|
||||||
|
poll() {
|
||||||
|
const media = []
|
||||||
|
for (let tracker of this._trackers)
|
||||||
|
media.push.apply(tracker.poll());
|
||||||
|
|
||||||
|
return media;
|
||||||
|
}
|
||||||
|
}
|
59
services/trackers/PlexTracker.js
Normal file
59
services/trackers/PlexTracker.js
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
const axios = require("axios");
|
||||||
|
const Song = require("../../models/song");
|
||||||
|
|
||||||
|
class PlexTracker {
|
||||||
|
constructor(config) {
|
||||||
|
this._config = config;
|
||||||
|
this._cache = []
|
||||||
|
}
|
||||||
|
|
||||||
|
async poll(useCache = false) {
|
||||||
|
if (!this._config.token || !this._config.url)
|
||||||
|
return [];
|
||||||
|
if (useCache)
|
||||||
|
return cache;
|
||||||
|
|
||||||
|
const response = await axios.get(this._config.url + "/status/sessions", {
|
||||||
|
headers: {
|
||||||
|
"Accept": "application/json",
|
||||||
|
"X-Plex-Token": this._config.token
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.data.MediaContainer?.Metadata) {
|
||||||
|
cache = [];
|
||||||
|
return cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
const filtered = response.data.MediaContainer?.Metadata.filter(m => this.#filter(m));
|
||||||
|
cache = filtered.map(this.#transform);
|
||||||
|
return cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
#filter(data) {
|
||||||
|
if (!this._config.filters || this._config.filters.length == 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
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))
|
||||||
|
continue;
|
||||||
|
if (filter.deviceId && !filter.deviceId.some(l => l == data.machineIdentifier))
|
||||||
|
continue;
|
||||||
|
if (filter.platform && !filter.platform.some(l => l == data.Player.platform))
|
||||||
|
continue;
|
||||||
|
if (filter.product && !filter.product.some(l => l == data.Player.product))
|
||||||
|
continue;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#transform(data) {
|
||||||
|
const id = data.guid.substring(data.guid.lastIndexOf('/') + 1);
|
||||||
|
return new Song(id, data.title, data.parentTitle, data.grandparentTitle, data.parentYear, data.duration, data.viewOffset, data.sessionKey, data.Player.state, "plex");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = PlexTracker;
|
83
services/trackers/SpotifyTracker.js
Normal file
83
services/trackers/SpotifyTracker.js
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
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;
|
Loading…
Reference in New Issue
Block a user