diff --git a/services/poll.js b/services/poll.js index 41643db..e7310c8 100644 --- a/services/poll.js +++ b/services/poll.js @@ -1,13 +1,15 @@ 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"); -const lastPlaying = {}; -const lastScrobbleTimes = {}; +let lastTick = Date.now(); async function poll() { const now = Date.now(); + const timeDiff = now - lastTick; const playing = []; await spotify.loadCredentials(); @@ -25,31 +27,50 @@ async function poll() { } for (let current of playing) { - const previous = lastPlaying[current.sessionKey]; - lastPlaying[current.sessionKey] = current; + 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 (checkIfCanScrobble(current, previous, now)) { + 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"); - lastScrobbleTimes[previous.mediaKey] = now; + 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; } } - // Scrobble then remove lingering sessions - for (let key in lastPlaying) { - if (!playing.some(p => p.sessionKey == key)) { - const track = lastPlaying[key]; - if (checkIfCanScrobble(null, track, now)) { - logger.info(track, "Scrobble"); - lastScrobbleTimes[track.mediaKey] = now; - } - delete lastPlaying[key]; - logger.debug("Deleted old session.", key); + 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) { @@ -72,7 +93,7 @@ function applyFilter(track, filters) { return false; } -function checkIfCanScrobble(current, previous, now) { +function checkIfCanScrobble(session, previous, now, timeDiff) { if (!previous) return false; @@ -85,20 +106,15 @@ function checkIfCanScrobble(current, previous, now) { return false; } - const scrobbleDuration = isInt(config.scrobble.minimum.duration) ? Number(config.scrobble.minimum.duration) : 30; - const scrobblePercent = isInt(config.scrobble.minimum.percent) ? Number(config.scrobble.minimum.percent) : 30; + const scrobbleDuration = config.scrobble.minimum.duration || 240; + const scrobblePercent = config.scrobble.minimum.percent || 50; - if (previous) { - const newPlayback = current == null || current.playtime < previous.playtime; - const canBeScrobbled = previous.playtime > scrobbleDuration * 1000 || previous.playtime / previous.duration > scrobblePercent; + 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; - if (newPlayback && canBeScrobbled) { - const sameSong = current != null && current.mediaKey == previous.mediaKey; - const lastTime = lastScrobbleTimes[previous.mediaKey]; - return !sameSong || !lastTime || now - lastTime > scrobbleDuration; - } - } - return false; + return newPlayback && canBeScrobbled; } function isInt(value) { diff --git a/services/spotify.js b/services/spotify.js index f0472d7..ee02fbf 100644 --- a/services/spotify.js +++ b/services/spotify.js @@ -34,7 +34,7 @@ async function refreshTokenIfNeeded() { } await fs.writeFile("credentials.spotify.json", JSON.stringify(data)); token = data; - logger.info("Updated access token for Spotify."); + logger.debug("Updated access token for Spotify."); return true; } catch (ex) { logger.error(ex, "Failed to get Spotify oauth.");