const plex = require("./plex"); const logger = require("./logging") const config = require("../config/configuration"); const lastPlaying = {}; const lastScrobbleTimes = {}; async function poll() { const now = Date.now(); const playing = []; 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) { const previous = lastPlaying[current.sessionKey]; lastPlaying[current.sessionKey] = current; if (previous == null) { continue; } let filters = []; if (previous.source == 'plex') filters = config.scrobble.plex.filters; if (!applyFilter(previous, filters)) { logger.debug(previous, 'No filters got triggered. Ignoring.'); continue; } if (!previous) { logger.info(current, "A new session has started."); } else { if (checkIfCanScrobble(current, previous, now)) { logger.info(previous, "Scrobble"); lastScrobbleTimes[previous.mediaKey] = 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); } } } function applyFilter(track, filters) { if (!filters) return; 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(current, last, now) { if (!last) return; 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; if (last) { const newPlayback = current == null || current.playtime < last.playtime; const canBeScrobbled = last.playtime > scrobbleDuration * 1000 || last.playtime / last.duration > scrobblePercent; if (newPlayback && canBeScrobbled) { const sameSong = current != null && current.mediaKey == last.mediaKey; const lastTime = lastScrobbleTimes[last.mediaKey]; return !sameSong || !lastTime || now - lastTime > scrobbleDuration; } } return false; } function isInt(value) { return !isNaN(value) && parseInt(Number(value)) == value && !isNaN(parseInt(value, 10)); } module.exports = poll;