Improved time upkeep for playing and pausing.

This commit is contained in:
Tom 2024-12-05 18:52:36 +00:00
parent 5100d18ac6
commit 0bfbc36952
2 changed files with 31 additions and 34 deletions

View File

@ -2,7 +2,8 @@ class Session {
#id = null;
#started = null;
#current = null;
#lastScrobble = null;
lastScrobbleTimestamp = 0;
lastUpdateTimestamp = 0;
pauseDuration = 0;
playDuration = 0;
@ -26,14 +27,6 @@ class Session {
get started() {
return this.#started;
}
get lastScrobbleTimestamp() {
return this.#lastScrobble;
}
set lastScrobbleTimestamp(value) {
this.#lastScrobble = value;
}
}
module.exports = Session;

View File

@ -8,7 +8,6 @@ class Recorder {
#scrobblers = [];
#config = null;
#logger = null;
#lastTick = null;
constructor(sessions, trackers, scrobblers, config, logger) {
this.#sessions = sessions;
@ -17,12 +16,10 @@ class Recorder {
this.#scrobblers = scrobblers;
this.#config = config;
this.#logger = logger;
this.#lastTick = Date.now();
}
async record() {
const now = Date.now();
const timeDiff = now - this.#lastTick;
const media = await this.#trackers.poll();
const contexts = media.map(m => this.#fetchContext(m));
@ -31,25 +28,30 @@ class Recorder {
const stopped = sessionIds.filter(sessionId => !contexts.some(context => sessionId == context.session.id))
.map(sessionId => this.#sessions.get(sessionId))
.map(session => this.#fetchContext(session.playing));
const contextEnded = stopped.filter(context => this.#canScrobble(context.session, null, context.session.playing, now));
const contextEnded = stopped.filter(context => this.#canScrobble(context.session, null, context.session.playing));
for (let context of contextEnded)
context.session.playDuration = now - (context.session.lastScrobbleTimestamp || context.session.started) - context.session.pauseDuration;
// Find ongoing sessions that have moved on to the next song.
const finishedPlaying = contexts.filter(context => this.#listen(context, now, timeDiff));
const finishedPlaying = contexts.filter(context => this.#listen(context, now));
// Scrobble
const scrobbling = finishedPlaying.concat(contextEnded);
for (let context of scrobbling)
for (let context of scrobbling) {
await this.#scrobble(context);
if (context.session.playing == null)
continue;
context.session.playDuration = context.extraDuration;
context.session.pauseDuration = 0;
}
// Remove dead sessions.
for (let context of stopped) {
this.#sessions.remove(context.session.id);
}
this.#lastTick = now;
}
#fetchContext(media) {
@ -60,39 +62,41 @@ class Recorder {
this.#sessions.add(session);
}
return { session, media, tracker }
return { session, media, tracker, extraDuration: 0 }
}
#listen(context, timestamp, timeDiff) {
#listen(context, timestamp) {
const session = context.session;
const current = context.media;
const previous = context.session.playing;
session.playing = current;
session.playDuration = timestamp - (session.lastScrobbleTimestamp || session.started) - session.pauseDuration;
if (!previous) {
this.#logger.info(current, "A new session has started.");
session.lastUpdateTimestamp = timestamp;
return false;
}
if (session.playing.state == "paused" || previous.state == "paused")
session.pauseDuration += timeDiff - (session.playing.progress - previous.progress);
const updated = current.progress != previous.progress || current.id != previous.id || current.state != previous.state;
if (!updated)
return false;
if (this.#canScrobble(session, current, previous, timestamp)) {
session.pauseDuration = 0;
session.lastScrobbleTimestamp = timestamp - (timeDiff - (previous.duration - previous.progress));
return true;
} else if (current.progress < previous.progress && session.playing.id != previous.id) {
session.pauseDuration = 0;
if (current.progress < timeDiff)
session.lastScrobbleTimestamp = timestamp - session.playing.progress;
else
session.lastScrobbleTimestamp = timestamp;
const timeDiff = timestamp - session.lastUpdateTimestamp;
const progressDiff = Math.max(0, Math.min(current.progress - previous.progress, timeDiff));
session.playDuration += progressDiff;
session.pauseDuration += timeDiff - progressDiff;
const canScrobble = this.#canScrobble(session, current, previous);
if (canScrobble || current.id != previous.id) {
context.extraDuration = Math.min(current.progress, timeDiff - (previous.duration - previous.progress));
session.lastScrobbleTimestamp = timestamp;
}
return false;
session.lastUpdateTimestamp = timestamp;
return canScrobble;
}
#canScrobble(session, current, previous, timestamp) {
#canScrobble(session, current, previous) {
if (previous == null)
return false;