Something went wrong. Try again.
[READ-ONLY] Mirror of https://github.com/FoxxMD/multi-scrobbler. Scrobble plays from multiple sources to multiple clients docs.multi-scrobbler.app
deezer docker jellyfin koito lastfm listenbrainz maloja mopidy mpris music music-assistant plex scrobble self-hosted spotify subsonic tautulli youtube-music
Something went wrong. Try again.
3.4 kB · 81 lines
TypeScript
at strict
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182import type {Dayjs} from "dayjs";import { type AbstractPlayerState } from "./AbstractPlayerState.ts";import type {PlayerStateDataMaybePlay} from "../../common/infrastructure/Atomic.ts";import { PositionalPlayerState } from "./PositionalPlayerState.ts";import { type ListenRange, ListenRangeTS } from "./ListenRange.ts";import { ListenProgressTS } from "./ListenProgress.ts";import { CALCULATED_PLAYER_STATUSES, type Second } from "../../../core/Atomic.ts";
export class SubsonicPlayerState extends PositionalPlayerState {
update(state: PlayerStateDataMaybePlay, reportedTS?: Dayjs) { const range = this.activeRange; const usesPosition = state.position !== undefined; if (range !== undefined && range.isPositional() !== usesPosition) { // Timestamp and position ranges measure different coordinates and cannot be combined -> Finalize the current listen session and start a new one afterwards. this.currentListenSessionEnd(); } return super.update(state, reportedTS); }
protected currentListenSessionContinue(position?: number, timestamp?: Dayjs) { if (position !== undefined) { return super.currentListenSessionContinue(position, timestamp); }
if (this.activeRange === undefined) { this.logger.debug('Started new Player listen range.'); this.activeRange = new ListenRangeTS(new ListenProgressTS({timestamp})); } else { this.calculatedStatus = CALCULATED_PLAYER_STATUSES.playing; this.activeRange.setRangeEnd(new ListenProgressTS({timestamp})); } }
protected currentListenSessionEnd() { const range = this.activeRange; if (range?.isPositional()) { return super.currentListenSessionEnd(); } if (range !== undefined && range.getDuration() !== 0) { this.logger.debug('Ended current Player listen range.'); range.finalize(); this.basePlayer.listenRanges.push(range); } this.activeRange = undefined; }
public getPosition(): Second | undefined { if (!this.activeRange?.isPositional()) { return this.activeRange?.getPosition(); } return super.getPosition(); }
protected isSessionRepeat(position?: number, reportedTS?: Dayjs) { if (this.activeRange?.isPositional()) { return super.isSessionRepeat(position, reportedTS); } // if track has a duration and the listened duration for this session is greater than 100% + 5% (for buffer) // then assume track is on repeat const duration = this.currentPlay?.data.duration; if(duration !== undefined && this.getListenDuration() > (duration + (0.05 * duration))) { this.logger.debug('Listened duration for this session is over 105%, triggering as a repeat'); return true; } return false; }
// Use base player listen range, to be able to set a timestamp-based listen range. private get basePlayer(): AbstractPlayerState { return this as AbstractPlayerState; }
private get activeRange(): ListenRange | undefined { return this.basePlayer.currentListenRange; }
private set activeRange(range: ListenRange | undefined) { this.basePlayer.currentListenRange = range; }}