From 242bacc1bedeec834358c681cf4e6b13a8181017 Mon Sep 17 00:00:00 2001 From: FoxxMD Date: Thu, 20 Mar 2025 15:40:31 +0000 Subject: [PATCH] feat(source): Optional position for non-positional sources * Allow non-positional Sources to still report position (for display only) * Refactor Azuracast to be non-positional due to reported position not always being accurate (azuracast approximates track length) --- src/backend/sources/AzuracastSource.ts | 8 ++------ src/backend/sources/MemoryPositionalSource.ts | 8 +++++++- src/backend/sources/MemorySource.ts | 4 +++- .../sources/PlayerState/AzuracastPlayerState.ts | 16 ---------------- .../sources/PlayerState/GenericPlayerState.ts | 6 +++--- .../sources/PlayerState/ListenProgress.ts | 6 ++++-- src/backend/sources/PlayerState/ListenRange.ts | 2 +- 7 files changed, 20 insertions(+), 30 deletions(-) delete mode 100644 src/backend/sources/PlayerState/AzuracastPlayerState.ts diff --git a/src/backend/sources/AzuracastSource.ts b/src/backend/sources/AzuracastSource.ts index d77ff173..d7bfa19a 100644 --- a/src/backend/sources/AzuracastSource.ts +++ b/src/backend/sources/AzuracastSource.ts @@ -1,5 +1,4 @@ -import { MemoryPositionalSource } from "./MemoryPositionalSource.js"; -import { sleep } from "../utils.js"; +import MemorySource from "./MemorySource.js"; import { RecentlyPlayedOptions } from "./AbstractSource.js"; import { childLogger, Logger } from "@foxxmd/logging"; import { EventEmitter } from "events"; @@ -17,11 +16,9 @@ import { } from "../common/infrastructure/Atomic.js"; import { AzuracastSourceConfig, AzuraNowPlayingResponse, AzuraStationResponse } from "../common/infrastructure/config/source/azuracast.js"; import { isPortReachable, normalizeWSAddress } from "../utils/NetworkUtils.js"; -import { PlayerStateOptions } from "./PlayerState/AbstractPlayerState.js"; -import { AzuracastPlayerState } from "./PlayerState/AzuracastPlayerState.js"; -export class AzuracastSource extends MemoryPositionalSource { +export class AzuracastSource extends MemorySource { declare config: AzuracastSourceConfig; @@ -230,7 +227,6 @@ export class AzuracastSource extends MemoryPositionalSource { return this.processRecentPlays([playerState]); } - getNewPlayer = (logger: Logger, id: PlayPlatformId, opts: PlayerStateOptions) => new AzuracastPlayerState(logger, id, opts); } const formatPlayObj = (obj: AzuraNowPlayingResponse, options: FormatPlayObjectOptions = {}): PlayObject => { diff --git a/src/backend/sources/MemoryPositionalSource.ts b/src/backend/sources/MemoryPositionalSource.ts index b8e07790..00297307 100644 --- a/src/backend/sources/MemoryPositionalSource.ts +++ b/src/backend/sources/MemoryPositionalSource.ts @@ -1,10 +1,16 @@ import { Logger } from "@foxxmd/logging"; -import { PlayerStateDataMaybePlay, PlayPlatformId } from "../common/infrastructure/Atomic.js"; +import { InternalConfig, PlayerStateDataMaybePlay, PlayPlatformId, SourceType } from "../common/infrastructure/Atomic.js"; import MemorySource from "./MemorySource.js"; import { PlayerStateOptions } from "./PlayerState/AbstractPlayerState.js"; import { PositionalPlayerState } from "./PlayerState/PositionalPlayerState.js"; import { PlayObject } from "../../core/Atomic.js"; +import { SourceConfig } from "../common/infrastructure/config/source/sources.js"; +import EventEmitter from "events"; export class MemoryPositionalSource extends MemorySource { + constructor(type: SourceType, name: string, config: SourceConfig, internal: InternalConfig, emitter: EventEmitter) { + super(type, name, config, internal, emitter); + this.isPositional = true; + } getNewPlayer = (logger: Logger, id: PlayPlatformId, opts: PlayerStateOptions) => new PositionalPlayerState(logger, id, opts) } \ No newline at end of file diff --git a/src/backend/sources/MemorySource.ts b/src/backend/sources/MemorySource.ts index 84c8a8f4..ce0565a6 100644 --- a/src/backend/sources/MemorySource.ts +++ b/src/backend/sources/MemorySource.ts @@ -52,6 +52,8 @@ export default class MemorySource extends AbstractSource { scheduler: ToadScheduler = new ToadScheduler(); + protected isPositional: boolean = false; + constructor(type: SourceType, name: string, config: SourceConfig, internal: InternalConfig, emitter: EventEmitter) { super(type, name, config, internal, emitter); @@ -331,7 +333,7 @@ export default class MemorySource extends AbstractSource { for(const player of this.players.values()) { if(player.calculatedStatus === CALCULATED_PLAYER_STATUSES.playing) { const pos = player.getPosition(); - if(pos !== undefined && player.currentPlay !== undefined && player.currentPlay.data?.duration !== undefined) { + if(pos !== undefined && this.isPositional && player.currentPlay !== undefined && player.currentPlay.data?.duration !== undefined) { const { data: { duration diff --git a/src/backend/sources/PlayerState/AzuracastPlayerState.ts b/src/backend/sources/PlayerState/AzuracastPlayerState.ts deleted file mode 100644 index 772808ba..00000000 --- a/src/backend/sources/PlayerState/AzuracastPlayerState.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { Logger } from "@foxxmd/logging"; -import { PlayPlatformId, REPORTED_PLAYER_STATUSES } from "../../common/infrastructure/Atomic.js"; -import { AbstractPlayerState, PlayerStateOptions } from "./AbstractPlayerState.js"; -import { GenericPlayerState } from "./GenericPlayerState.js"; -import { PositionalPlayerState } from "./PositionalPlayerState.js"; - -export class AzuracastPlayerState extends PositionalPlayerState { - constructor(logger: Logger, platformId: PlayPlatformId, opts?: PlayerStateOptions) { - super(logger, platformId, {allowedDrift: 17000, rtTruth: true, ...(opts || {})}); - this.gracefulEndBuffer = this.allowedDrift / 1000; - } - - protected isSessionStillPlaying(position: number): boolean { - return this.reportedStatus === REPORTED_PLAYER_STATUSES.playing; - } -} diff --git a/src/backend/sources/PlayerState/GenericPlayerState.ts b/src/backend/sources/PlayerState/GenericPlayerState.ts index 01f9a1a0..41c4aa7c 100644 --- a/src/backend/sources/PlayerState/GenericPlayerState.ts +++ b/src/backend/sources/PlayerState/GenericPlayerState.ts @@ -19,13 +19,13 @@ export class GenericPlayerState extends AbstractPlayerState { super(logger, platformId, opts); } - protected currentListenSessionContinue(position: number = 0, timestamp?: Dayjs) { + protected currentListenSessionContinue(position?: number, timestamp?: Dayjs) { if (this.currentListenRange === undefined) { this.logger.debug('Started new Player listen range.'); - this.currentListenRange = this.newListenRange(this.newListenProgress({timestamp})); + this.currentListenRange = this.newListenRange(this.newListenProgress({position, timestamp})); } else { this.calculatedStatus = CALCULATED_PLAYER_STATUSES.playing; - this.currentListenRange.setRangeEnd(this.newListenProgress({timestamp})); + this.currentListenRange.setRangeEnd(this.newListenProgress({position, timestamp})); } } diff --git a/src/backend/sources/PlayerState/ListenProgress.ts b/src/backend/sources/PlayerState/ListenProgress.ts index 9b2612c9..ac517189 100644 --- a/src/backend/sources/PlayerState/ListenProgress.ts +++ b/src/backend/sources/PlayerState/ListenProgress.ts @@ -6,11 +6,13 @@ export class ListenProgressTS implements PlayProgress { public timestamp: Dayjs; public positionPercent?: number; + public position?: Second; constructor(data: Partial = {}) { - const {timestamp, positionPercent} = data; + const {timestamp, positionPercent, position} = data; this.timestamp = timestamp ?? dayjs(); this.positionPercent = positionPercent; + this.position = position; } getDuration(end: ListenProgressTS): Second { @@ -27,7 +29,7 @@ export class ListenProgressTS implements PlayProgress { } export class ListenProgressPositional extends ListenProgressTS implements PlayProgressPositional { - public position: Second; + declare public position: Second; constructor(data: PlayProgressPositional) { super(data); diff --git a/src/backend/sources/PlayerState/ListenRange.ts b/src/backend/sources/PlayerState/ListenRange.ts index 7bf1c44a..5084d62d 100644 --- a/src/backend/sources/PlayerState/ListenRange.ts +++ b/src/backend/sources/PlayerState/ListenRange.ts @@ -66,7 +66,7 @@ export class ListenRangeTS extends ListenRange implements ListenRangeData { } public getPosition(): Second { - return undefined; + return this.end.position; } public finalize(position?: number) { -- 2.51.2