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.4 kB · 111 lines
TypeScript
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111import { childLogger, type Logger } from "@foxxmd/logging";import type EventEmitter from "events";import normalizeUrl from "normalize-url";import {COMPONENT_AUTH_TYPE, type ComponentAuthType, type PlayObject} from "../../core/Atomic.ts";import { capitalize } from "../../core/StringUtils.ts";import { buildTrackString } from "../../core/MusicMetadata.ts";import { isNodeNetworkException } from "../common/errors/NodeErrors.ts";import type {FormatPlayObjectOptions, TimeRangeListensFetcher} from "../common/infrastructure/Atomic.ts";import type {MalojaClientConfig} from "../common/infrastructure/config/client/maloja.ts";import type {MalojaScrobbleRequestData} from "../common/vendor/maloja/interfaces.ts";import AbstractScrobbleClient from "./AbstractScrobbleClient.ts";import { MalojaApiClient, formatPlayObj as formatMalojaScrobbleToPlay, playToScrobblePayload } from "../common/vendor/maloja/MalojaApiClient.ts";import { createGetScrobblesForTimeRangeFunc } from "../utils/ListenFetchUtils.ts";
const feat = ["ft.", "ft", "feat.", "feat", "featuring", "Ft.", "Ft", "Feat.", "Feat", "Featuring"];
export default class MalojaScrobbler extends AbstractScrobbleClient {
override authType: ComponentAuthType = COMPONENT_AUTH_TYPE.unattended; requiresAuth = true; serverVersion: any; webUrl!: string;
api: MalojaApiClient; getScrobblesForTimeRange: TimeRangeListensFetcher
declare config: MalojaClientConfig
constructor(name: any, config: MalojaClientConfig, emitter: EventEmitter, logger: Logger) { super('maloja', name, config, emitter, logger); this.api = new MalojaApiClient(name, this.config.data, { logger: childLogger(this.logger, 'API') }); this.MAX_INITIAL_SCROBBLES_FETCH = 100; this.getScrobblesForTimeRange = createGetScrobblesForTimeRangeFunc(this.api, this.api.logger); }
formatPlayObj = (obj: any, options: FormatPlayObjectOptions = {}) => formatMalojaScrobbleToPlay(obj, { url: this.webUrl });
protected async doBuildInitData(): Promise<true | string | undefined> { const { data: { url, apiKey } = {} } = this.config; if (apiKey === undefined) { throw new Error("'apiKey' not found in config!"); } if (url === undefined) { throw new Error("Missing 'url' for Maloja config"); } this.webUrl = normalizeUrl(url); return true; }
protected async doCheckConnection(): Promise<true | string | undefined> {
try { await this.api.testConnection(); await this.api.testHealth(); return true; } catch (e) { throw e; }
}
doAuthentication = async () => {
const { data: { url, apiKey } = {} } = this.config; if (apiKey === undefined) { throw new Error("'apiKey' not found in config!"); } try { await this.api.testAuth(); return true; } catch (e) { if (isNodeNetworkException(e)) { this.logger.error('Could not communicate with Maloja API'); } throw e; } } public playToClientPayload(playObj: PlayObject): MalojaScrobbleRequestData {
const { apiKey } = this.config.data;
return playToScrobblePayload(playObj); }
doScrobble = async (playObj: PlayObject) => { const { meta: { source, newFromSource = false, } = {} } = playObj;
const scrobbleData = playToScrobblePayload(playObj);
try { const result = await this.api.scrobble(playObj); const scrobbleInfo = `Scrobbled (${newFromSource ? 'New' : 'Backlog'}) => (${source}) ${buildTrackString(playObj)}`; if (result.warnings !== undefined && result.warnings.length > 0) { this.logger.warn(`${scrobbleInfo} | ${result.warnings.join(' | ')}`); } else { this.logger.info(scrobbleInfo); } return result; } catch (e: any) { await this.notify({ title: `Client - ${capitalize(this.type)} - ${this.name} - Scrobble Error`, message: `Failed to scrobble => ${buildTrackString(playObj)} | Error: ${e.message}`, priority: 'error' }); throw e; } }}