From 3112a29bb3ee30d5fe3c3a38b22e45c06c96cdad Mon Sep 17 00:00:00 2001 From: Tom Date: Tue, 3 Dec 2024 23:58:15 +0000 Subject: [PATCH] Added basic filtering to Plex scrobbling detection. --- app.js | 7 ++--- config/configuration.js | 30 +++++++++++++++++----- services/plex.js | 1 + services/poll.js | 57 +++++++++++++++++++++++++++++++---------- 4 files changed, 71 insertions(+), 24 deletions(-) diff --git a/app.js b/app.js index 26d1a8b..948a093 100644 --- a/app.js +++ b/app.js @@ -1,11 +1,8 @@ -const dotenv = require('dotenv'); +const config = require("./config/configuration"); const express = require('express'); const helmet = require("helmet"); -const rateLimit = require("express-rate-limit"); -const config = require("./config/configuration"); const logger = require("./services/logging"); - -dotenv.config(); +const rateLimit = require("express-rate-limit"); const poll = require("./services/poll"); setInterval(poll, 5000); diff --git a/config/configuration.js b/config/configuration.js index 7e9549a..0b3cdfb 100644 --- a/config/configuration.js +++ b/config/configuration.js @@ -6,8 +6,21 @@ const configuration = { token: null }, scrobble: { - percent: null, - duration: null + minimum: { + percent: null, + duration: null + }, + plex: { + delay: null, + filters: [] + /* A filter will have the following properties: + library: [""], + ip: [""], + deviceId: [""], + platform: [""], + product: [""] + */ + }, }, web: { host: null, @@ -20,10 +33,15 @@ if (config.has("plex.url")) if (config.has("plex.token")) configuration.plex.token = config.get("plex.token"); -if (config.has("scrobble.duration")) - configuration.scrobble.duration = config.get("scrobble.duration"); -if (config.has("scrobble.percent")) - configuration.scrobble.percent = config.get("scrobble.percent"); +if (config.has("scrobble.plex.delay")) + configuration.scrobble.plex.delay = config.get("scrobble.plex.delay"); +if (config.has("scrobble.plex.filters")) + configuration.scrobble.plex.filters = config.get("scrobble.plex.filters"); + +if (config.has("scrobble.minimum.duration")) + configuration.scrobble.minimum.duration = config.get("scrobble.minimum.duration"); +if (config.has("scrobble.minimum.percent")) + configuration.scrobble.minimum.percent = config.get("scrobble.minimum.percent"); if (config.has("web.host")) configuration.web.host = config.get("web.host"); diff --git a/services/plex.js b/services/plex.js index 6490583..70b729e 100644 --- a/services/plex.js +++ b/services/plex.js @@ -43,6 +43,7 @@ async function getCurrentlyPlaying(cached = false) { "platformVersion": media.Player.platformVersion, "product": media.Player.product, "version": media.Player.version, + "source": "plex" })); return cache[key]; } diff --git a/services/poll.js b/services/poll.js index 534946f..368536e 100644 --- a/services/poll.js +++ b/services/poll.js @@ -17,22 +17,30 @@ async function poll() { return; } - for (let media of playing) { - if (!lastScrobbleTimes[media.mediaKey]) { - lastScrobbleTimes[media.mediaKey] = 1; + for (let current of playing) { + const previous = lastPlaying[current.sessionKey]; + lastPlaying[current.sessionKey] = current; + if (previous == null) { + continue; } - const lastTrack = lastPlaying[media.sessionKey]; - if (!lastTrack) { - logger.info(media, "A new session has started."); + 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(media, lastTrack, now)) { - logger.info(lastTrack, "Scrobble"); - lastScrobbleTimes[lastTrack.mediaKey] = now; + if (checkIfCanScrobble(current, previous, now)) { + logger.info(previous, "Scrobble"); + lastScrobbleTimes[previous.mediaKey] = now; } } - - lastPlaying[media.sessionKey] = media; } // Scrobble then remove lingering sessions @@ -49,9 +57,32 @@ async function poll() { } } +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) { - const scrobbleDuration = isInt(config.scrobble.duration) ? Number(config.scrobble.duration) : 30; - const scrobblePercent = isInt(config.scrobble.percent) ? Number(config.scrobble.percent) : 30; + 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;