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.
4.9 kB · 116 lines
TypeScript
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117import type EventEmitter from "events";import { COMPONENT_AUTH_TYPE, type ComponentAuthType, PARSED_FROM, type PlayObject, SOURCE_SOT } from "../../core/Atomic.ts";import type {FormatPlayObjectOptions, InternalConfig} from "../common/infrastructure/Atomic.ts";import type {RecentlyPlayedOptions} from "./AbstractSource.ts";import MemorySource from "./MemorySource.ts";import { TealApiUnauthenticatedClient } from "../common/vendor/teal/TealApiClient.ts";import { recordToPlay } from "../common/vendor/teal/TealApiClient.ts";import type {TealSourceConfig} from "../common/infrastructure/config/source/tealfm.ts";import { ATProtoAppApiClient } from "../common/vendor/atproto/ATProtoAppApiClient.ts";import { parseArrayFromMaybeString } from "../utils/StringUtils.ts";
export default class TealfmSource extends MemorySource {
client: TealApiUnauthenticatedClient; override authType: ComponentAuthType = COMPONENT_AUTH_TYPE.unattended; requiresAuth = true; requiresAuthInteraction = false;
serviceAllow: string[] serviceDeny: string[]
declare config: TealSourceConfig;
constructor(name: any, config: TealSourceConfig, internal: InternalConfig, emitter: EventEmitter) { const { data: { interval = 15, maxInterval = 60, ...restData } = {} } = config; super('tealfm', name, {...config, data: {interval, maxInterval, ...restData}}, internal, emitter); this.canPoll = true; this.canBacklog = true; this.client = new TealApiUnauthenticatedClient(name, config.data, {...internal, logger: internal.logger}); this.playerSourceOfTruth = SOURCE_SOT.HISTORY; this.supportsUpstreamRecentlyPlayed = true this.SCROBBLE_BACKLOG_COUNT = 20; }
static formatPlayObj(obj: any, options: FormatPlayObjectOptions = {}){ return recordToPlay(obj); }
protected async doBuildInitData(): Promise<true | string | undefined> { const { data: { identifier, serviceAllow = [], serviceDeny = [] } = {} } = this.config; if (identifier === undefined) { throw new Error('Must provide an identifier'); }
await this.client.client.initClient();
this.serviceAllow = parseArrayFromMaybeString(serviceAllow, {lower: true}); if(this.serviceAllow.length > 0) { this.logger.debug(`Discover Plays from these services only: ${this.serviceAllow.join(',')}`); } else { this.serviceDeny = parseArrayFromMaybeString(serviceDeny, {lower: true}); if(this.serviceDeny.length > 0) { this.logger.debug(`Do not discover Plays from these services: ${this.serviceDeny.join(',')}`); } }
return true; }
protected async doCheckConnection(): Promise<true | string | undefined> { if (this.client instanceof ATProtoAppApiClient) { try { return await this.client.checkPds(this.config.data); } catch (e) { throw e; } } else { return true; } }
getRecentlyPlayed = async(options: RecentlyPlayedOptions = {}) => { const {limit = 20} = options; let plays: PlayObject[]; this.setStatus('Checking for new Plays'); try { const {data} = await this.client.getPagelessTimeRangeListens({limit}) plays = data; } catch (e) { throw new Error('Error occurred while trying to fetch records', {cause: e}); } await this.processRecentPlays([]); if(this.serviceAllow.length > 0) { plays = plays.filter(x => (x.meta.musicService !== undefined && this.serviceAllow.some(y => x.meta.musicService.toLocaleLowerCase().includes(y))) || (x.meta.musicService === undefined && this.serviceAllow.includes('unknown')) ); } else if(this.serviceDeny.length > 0) { plays = plays.filter(x => (x.meta.musicService !== undefined && !this.serviceDeny.some(y => x.meta.musicService.toLocaleLowerCase().includes(y))) || (x.meta.musicService === undefined && !this.serviceAllow.includes('unknown')) ); } return plays.map((x) => ({...x, meta: {...x.meta, parsedFrom: PARSED_FROM.history}})); }
getUpstreamRecentlyPlayed = async (options: RecentlyPlayedOptions = {}): Promise<PlayObject[]> => { try { return await this.getRecentlyPlayed(options); } catch (e) { throw e; } }
protected getBackloggedPlays = async (options: RecentlyPlayedOptions = {}) => await this.getRecentlyPlayed({formatted: true, ...options})}