From 08ab059ff7bbda5dab302bfda54f13e3b218120a Mon Sep 17 00:00:00 2001 From: FoxxMD Date: Wed, 30 Sep 2026 18:18:05 +0000 Subject: [PATCH] feat(koito): Add includePlayPosition to koito scrobbler implementation --- .../common/infrastructure/config/client/koito.ts | 2 ++ src/backend/common/vendor/koito/KoitoApiClient.ts | 12 +++++++++--- src/backend/scrobblers/KoitoScrobbler.ts | 2 +- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/backend/common/infrastructure/config/client/koito.ts b/src/backend/common/infrastructure/config/client/koito.ts index e23919f4..bf2d69f7 100644 --- a/src/backend/common/infrastructure/config/client/koito.ts +++ b/src/backend/common/infrastructure/config/client/koito.ts @@ -4,6 +4,7 @@ import {componentTypeSchema} from "../../../../../core/Atomic.ts"; import {allowDeviceListEnvSchema, allowDeviceListSchema, requestRetryOptionsSchema} from "../common.ts"; import {commonClientConfigSchema, commonClientDataSchema, commonClientOptionsSchema, nowPlayingOptionsSchema, type EnvClientSchema} from "./index.ts"; import { httpUrl } from "../../../../utils/ZodUtils.ts"; +import { listenbrainzOptionsSchema } from "./listenbrainz.ts"; export interface ListensResponse { items: ListenObjectResponse[] @@ -89,6 +90,7 @@ export const koitoOptionsSchema = z.object({ * @examples [{"iphone": "", "9f3ec2-iphone": "kitchen ipad"}] * */ allowDeviceList: allowDeviceListSchema, + includePlayPosition: listenbrainzOptionsSchema.shape.includePlayPosition.meta(listenbrainzOptionsSchema.shape.includePlayPosition.meta() ?? {}), ...commonClientOptionsSchema.shape, ...nowPlayingOptionsSchema.shape, }); diff --git a/src/backend/common/vendor/koito/KoitoApiClient.ts b/src/backend/common/vendor/koito/KoitoApiClient.ts index c44c5dd3..c31dde1d 100644 --- a/src/backend/common/vendor/koito/KoitoApiClient.ts +++ b/src/backend/common/vendor/koito/KoitoApiClient.ts @@ -23,16 +23,17 @@ interface SubmitOptions { listenType?: ListenType /** See matchDeviceLabel in lzUtils */ allowDeviceList?: AllowDeviceList + includePlayPosition?: boolean } const KOITO_LZ_PATH: RegExp = new RegExp(/^\/apis\/listenbrainz(\/?1?\/?)?$/); export class KoitoApiClient extends AbstractApiClient implements PaginatedTimeRangeListens { - declare config: KoitoData & {allowDeviceList?: AllowDeviceList}; + declare config: KoitoData & {allowDeviceList?: AllowDeviceList, includePlayPosition?: boolean}; url: URLData; - constructor(name: any, config: KoitoData & {allowDeviceList?: AllowDeviceList}, options: AbstractApiOptions) { + constructor(name: any, config: KoitoData & {allowDeviceList?: AllowDeviceList, includePlayPosition?: boolean}, options: AbstractApiOptions) { super('Koito', name, config, options); const { @@ -197,7 +198,12 @@ export class KoitoApiClient extends AbstractApiClient implements PaginatedTimeRa submitListen = async (play: PlayObject, options: SubmitOptions = {}): Promise => { const { log = false, listenType = 'single', allowDeviceList = this.config.allowDeviceList } = options; - const listenPayload: SubmitPayload = { listen_type: listenType, payload: [playToListenPayload(play, {allowDeviceList})] }; + const listenPayload: SubmitPayload = { listen_type: listenType, payload: [ + playToListenPayload(play, { + allowDeviceList, + includePlayPosition: options.listenType === 'playing_now' && (options.includePlayPosition ?? this.config.includePlayPosition) + }) + ] }; try { if (listenType === 'playing_now') { delete listenPayload.payload[0].listened_at; diff --git a/src/backend/scrobblers/KoitoScrobbler.ts b/src/backend/scrobblers/KoitoScrobbler.ts index 4552cae0..8cb949c1 100644 --- a/src/backend/scrobblers/KoitoScrobbler.ts +++ b/src/backend/scrobblers/KoitoScrobbler.ts @@ -23,7 +23,7 @@ export default class KoitoScrobbler extends AbstractScrobbleClient { constructor(name: any, config: KoitoClientConfig, options = {}, emitter: EventEmitter, logger: Logger) { super('koito', name, config, emitter, logger); - this.api = new KoitoApiClient(name, {...config.data, allowDeviceList: config.options?.allowDeviceList}, {logger: this.logger}); + this.api = new KoitoApiClient(name, {...config.data, allowDeviceList: config.options?.allowDeviceList, includePlayPosition: config.options?.includePlayPosition}, {logger: this.logger}); // https://listenbrainz.readthedocs.io/en/latest/users/api/core.html#get--1-user-(user_name)-listens // 1000 is way too high. maxing at 100 this.MAX_INITIAL_SCROBBLES_FETCH = 100; -- 2.51.2