Skip to content

Commit

Permalink
Implement basic player state
Browse files Browse the repository at this point in the history
  • Loading branch information
FoxxMD committed Aug 8, 2023
1 parent 51d16c9 commit 8579715
Show file tree
Hide file tree
Showing 2 changed files with 118 additions and 5 deletions.
26 changes: 21 additions & 5 deletions src/common/infrastructure/Atomic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,24 +31,30 @@ export interface InternalConfig {
logger: Logger
}

export type ReportedPlayerStatus = 'playing' | 'stopped' | 'paused' | 'unknown';
export const REPORTED_PLAYER_STATUSES = {
playing: 'playing' as ReportedPlayerStatus,
stopped: 'stopped' as ReportedPlayerStatus,
paused: 'paused' as ReportedPlayerStatus,
unknown: 'unknown' as ReportedPlayerStatus
}

export interface ConfigMeta {
source: string
mode?: string
configureAs: string
}

export interface PlayData {
export type ListenRange = [Dayjs, Dayjs]

export interface TrackData {
artists?: string[]
album?: string
track?: string
/**
* The length of the track, in seconds
* */
duration?: number
/**
* The date the track was played at
* */
playDate?: Dayjs

meta?: {
brainz?: {
Expand All @@ -61,6 +67,16 @@ export interface PlayData {
}
}

export interface PlayData extends TrackData {
/**
* The date the track was played at
* */
playDate?: Dayjs
/** Number of seconds the track was listened to */
listenedFor?: number
listenRanges?: ListenRange[]
}

export interface PlayMeta {
source?: string

Expand Down
97 changes: 97 additions & 0 deletions src/sources/PlayerState/AbstractPlayerState.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import {
ListenRange, PlayData,
PlayObject,
PlayPlatformId,
REPORTED_PLAYER_STATUSES,
ReportedPlayerStatus
} from "../../common/infrastructure/Atomic.js";
import dayjs, {Dayjs} from "dayjs";
import {playObjDataMatch} from "../../utils.js";

export abstract class AbstractPlayerState {
reportedStatus: ReportedPlayerStatus = REPORTED_PLAYER_STATUSES.unknown
platformId: PlayPlatformId
currentPlay?: PlayObject
playFirstSeenAt?: Dayjs
currentListenRange?: ListenRange
listenRanges: ListenRange[] = [];

protected constructor(platformId: PlayPlatformId, initialPlay?: PlayObject, status?: ReportedPlayerStatus) {
this.platformId = platformId;
if(initialPlay !== undefined) {
this.setPlay(initialPlay, status);
}
}

platformEquals(candidateId: PlayPlatformId) {
return this.platformId[0] === candidateId[0] && this.platformId[1] === candidateId[0];
}

// TODO track player position from PlayObject against listen session

setPlay(play: PlayObject, status: ReportedPlayerStatus = 'playing'): [PlayObject, PlayObject?] {
if (this.currentPlay !== undefined) {
if (!playObjDataMatch(this.currentPlay, play)/* || (true !== false)*/) { // TODO check new play date and listen range to see if they intersect
this.currentListenSessionEnd();
const played = this.getPlayedObject();
this.setCurrentPlay(play);
return [this.getPlayedObject(), played];
} else if (status === 'playing') {
this.currentListenSessionContinue();
} else {
this.currentListenSessionEnd();
}
} else {
this.setCurrentPlay(play);
return [this.getPlayedObject(), undefined];
}
}

getPlayedObject(): PlayObject {
return {
data: {
...this.currentPlay.data,
playDate: this.playFirstSeenAt,
listenedFor: this.getListenDuration(),
listenRanges: this.listenRanges
},
meta: this.currentPlay.meta
}
}

getListenDuration() {
let listenDur: number = 0;
for (const [start, end] of this.listenRanges) {
const dur = start.diff(end, 'seconds');
listenDur += dur;
}
return listenDur;
}

currentListenSessionContinue() {
const now = dayjs();
if (this.currentListenRange === undefined) {
this.currentListenRange = [now, now];
} else {
this.currentListenRange = [this.currentListenRange[0], now];
}
}

currentListenSessionEnd() {
if (this.currentListenRange !== undefined && this.currentListenRange[0].unix() !== this.currentListenRange[1].unix()) {
this.listenRanges.push(this.currentListenRange);
}
this.currentListenRange = undefined;
}

setCurrentPlay(play: PlayObject, status: ReportedPlayerStatus = 'playing') {
this.currentPlay = play;
this.playFirstSeenAt = dayjs();
this.reportedStatus = status;
this.listenRanges = [];
this.currentListenRange = undefined;
if (status === 'playing') {
this.currentListenSessionContinue();
}
}
}

0 comments on commit 8579715

Please sign in to comment.