apollo/services/poll.js

126 lines
3.9 KiB
JavaScript

const plex = require("./plex");
const logger = require("./logging")
const config = require("../config/configuration");
const Session = require("../models/session");
const sessions = require("../services/session-manager");
const spotify = require("./spotify");
let lastTick = Date.now();
async function poll() {
const now = Date.now();
const timeDiff = now - lastTick;
const playing = [];
await spotify.loadCredentials();
await spotify.refreshTokenIfNeeded();
const spotifyTrack = await spotify.getCurrentlyPlaying();
if (spotifyTrack != null)
playing.push(spotifyTrack);
try {
const data = await plex.getCurrentlyPlaying();
playing.push.apply(playing, data);
} catch (ex) {
logger.error(ex, "Could not fetch currently playing data from Plex.");
return;
}
for (let current of playing) {
let session = sessions.get(current.sessionKey);
if (session == null) {
session = new Session(current.sessionKey);
sessions.add(session);
}
const previous = session.playing;
session.playing = current;
if (previous == null) {
logger.info(current, "A new session has started.");
continue;
}
if (session.playing.state == "paused" || previous.state == "paused") {
session.pauseDuration += timeDiff - (session.playing.playtime - previous.playtime);
}
if (checkIfCanScrobble(session, previous, now, timeDiff)) {
logger.info(previous, "Scrobble");
session.pauseDuration = 0;
session.lastScrobbleTimestamp = now - (timeDiff - (previous.duration - previous.playtime));
} else if (session.playing.playtime < previous.playtime && session.playing.mediaKey != previous.mediaKey) {
session.pauseDuration = 0;
if (session.playing.playtime < timeDiff)
session.lastScrobbleTimestamp = now - session.playing.playtime;
else
session.lastScrobbleTimestamp = now;
}
}
const ids = sessions.getSessionIds();
for (let sessionId of ids) {
if (playing.some(p => p.sessionKey == sessionId))
continue;
session.playing = null;
if (checkIfCanScrobble(session, session.playing, now, timeDiff)) {
logger.info(session.playing, "Scrobble");
}
sessions.remove(sessionId);
logger.debug("Deleted old session (" + sessionId + ")");
}
lastTick = now;
}
function applyFilter(track, filters) {
if (!filters || filters.length == 0)
return true;
for (let filter of filters) {
if (filter.library && !filter.library.some(l => l == track.library))
continue;
if (filter.ip && !filter.ip.some(l => l == track.ip))
continue;
if (filter.deviceId && !filter.deviceId.some(l => l == track.deviceId))
continue;
if (filter.platform && !filter.platform.some(l => l == track.platform))
continue;
if (filter.product && !filter.product.some(l => l == track.product))
continue;
return true;
}
return false;
}
function checkIfCanScrobble(session, previous, now, timeDiff) {
if (!previous)
return false;
let filters = [];
if (previous.source == 'plex')
filters = config.plex.filters;
if (!applyFilter(previous, filters)) {
logger.debug(previous, 'No filters got triggered. Ignoring.');
return false;
}
const scrobbleDuration = config.scrobble.minimum.duration || 240;
const scrobblePercent = config.scrobble.minimum.percent || 50;
const current = session.playing;
const durationPlayed = now - (session.lastScrobbleTimestamp ?? session.started) - session.pauseDuration;
const newPlayback = current == null || current.playtime < previous.playtime && current.playtime < timeDiff;
const canBeScrobbled = durationPlayed > scrobbleDuration * 1000 || durationPlayed / previous.duration > scrobblePercent / 100.0;
return newPlayback && canBeScrobbled;
}
function isInt(value) {
return !isNaN(value) &&
parseInt(Number(value)) == value &&
!isNaN(parseInt(value, 10));
}
module.exports = poll;