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.6 kB · 80 lines
TypeScript
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081import type EventEmitter from "events";import { COMPONENT_AUTH_TYPE, type ComponentAuthType, PARSED_FROM, type PlayObject, SOURCE_SOT } from "../../core/Atomic.ts";import { isNodeNetworkException } from "../common/errors/NodeErrors.ts";import type {FormatPlayObjectOptions, InternalConfig, TimeRangeListensFetcher} from "../common/infrastructure/Atomic.ts";import type {RecentlyPlayedOptions} from "./AbstractSource.ts";import MemorySource from "./MemorySource.ts";import { KoitoApiClient, listenObjectResponseToPlay } from "../common/vendor/koito/KoitoApiClient.ts";import type {KoitoSourceConfig} from "../common/infrastructure/config/source/koito.ts";import { createGetScrobblesForTimeRangeFunc } from "../utils/ListenFetchUtils.ts";
export default class KoitoSource extends MemorySource {
api: KoitoApiClient; override authType: ComponentAuthType = COMPONENT_AUTH_TYPE.unattended; requiresAuth = true; requiresAuthInteraction = false; getScrobblesForTimeRange: TimeRangeListensFetcher
declare config: KoitoSourceConfig;
constructor(name: any, config: KoitoSourceConfig, internal: InternalConfig, emitter: EventEmitter) { const { data: { interval = 15, maxInterval = 60, ...restData } = {} } = config; super('koito', name, {...config, data: {interval, maxInterval, ...restData}}, internal, emitter); this.canPoll = true; this.canBacklog = true; this.api = new KoitoApiClient(name, config.data, {logger: this.logger}); this.playerSourceOfTruth = SOURCE_SOT.HISTORY; this.supportsUpstreamRecentlyPlayed = true this.SCROBBLE_BACKLOG_COUNT = 100; this.logger.info(`Note: The player for this source is an analogue for the 'Now Playing' status exposed by ${this.type} which is NOT used for scrobbling. Instead, the 'recently played' or 'history' information provided by this source is used for scrobbles.`) this.getScrobblesForTimeRange = createGetScrobblesForTimeRangeFunc(this.api, this.api.logger); }
static formatPlayObj(obj: any, options: FormatPlayObjectOptions = {}){ return listenObjectResponseToPlay(obj, options); }
protected async doCheckConnection(): Promise<true | string | undefined> { await this.api.testConnection(); return true; }
doAuthentication = async () => { if(this.config.data.token === undefined) { throw new Error('Must provide a User Token in configuration'); } try { return await this.api.testAuth(); } catch (e) { if(isNodeNetworkException(e)) { this.logger.error('Could not communicate with Koito API'); } throw e; } }
getRecentlyPlayed = async(options: RecentlyPlayedOptions = {}) => { const {limit = 20} = options; this.setStatus('Checking for new Plays'); await this.processRecentPlays([]); const resp = await this.getScrobblesForTimeRange({limit, cursor: 0 }); return resp.map((x) => ({...x, meta: {...x.meta, parsedFrom: PARSED_FROM.history}})); }
getUpstreamRecentlyPlayed = async (options: RecentlyPlayedOptions = {}): Promise<PlayObject[]> => { try { const resp = await this.getScrobblesForTimeRange({limit: 20, cursor: 0 }); return resp; } catch (e) { throw e; } }
protected getBackloggedPlays = async (options: RecentlyPlayedOptions = {}) => await this.getRecentlyPlayed({formatted: true, ...options})}